说明
装饰器设计模式是使用比较频繁的设计模式,它在不改变原物体的情况对原物体实现了功能的增加,原物体还是一个可单独使用的个体。在JAVA的类库中应该会马上想到IO类,各种的InputStrem,OutputStrem。
装饰器模式
在用户登录的中过程,我们需要对用户输入的密码进行加密操作,在设计时会提供好多种加密的算法,例如简单的BASE64加密,复杂的如MD5、DSA加密。直接把用户的密码存入数据库是真的在耍流氓。在使用这些算法时,我们想灵活的使用,比如使用完简单加密还可以再进行一下MD5的加密。针对这样的需求,可以使用装饰器模式进行实现。大体思路如下:
- 加密接口,定义加密方法。
- 在装饰器中,最原始的被装饰者是目标实现,它们一般会实现加密定义的具体方法。
- 装饰者会针对目标对象进行装饰,所以它要同样实现加密接口的方法,一般情况下这个装饰器会定义为抽象的形式,在这个装饰器父类中维护着对目标对象的引用。
- 具体装饰器继承抽象装饰器来实现对目标对象的真正装饰操作。
以上的情况在代码上体现为如下形式:
- 加密接口
package cn.imcompany.decorator.encrypt;
/**
* Created by tomyli on 2018/6/25.
* Github: https://github.com/peng051410
*/
public interface Encryptor {
void encrypt();
}
- 具体加密类,实现加密处理接口
package cn.imcompany.decorator.encrypt;
/**
* Created by tomyli on 2018/6/25.
* Github: https://github.com/peng051410
*/
public class ConcreteEncryptor implements Encryptor {
@Override
public void encrypt() {
System.out.println("base encrypt!");
}
}
- 抽象加密装饰器
package cn.imcompany.decorator.encrypt;
/**
* Created by tomyli on 2018/6/25.
* Github: https://github.com/peng051410
*/
public abstract class EncryptDecorator implements Encryptor {
private Encryptor encrypt;
public EncryptDecorator(Encryptor encrypt) {
this.encrypt = encrypt;
}
@Override
public void encrypt() {
encrypt.encrypt();
}
}
上面的抽象装饰器实现的加密接口,在这个类中维护加密接口的实体,加密方法直接调用其维护实体的加密方法。
- 具体的装饰器实现类
package cn.imcompany.decorator.encrypt;
/**
* Created by tomyli on 2018/6/25.
* Github: https://github.com/peng051410
*/
public class ModEncryptDecorator extends EncryptDecorator {
public ModEncryptDecorator(Encryptor encrypt) {
super(encrypt);
}
@Override
public void encrypt() {
super.encrypt();
modEncrypt();
}
public void modEncrypt() {
System.out.println("取模加密!");
}
}
package cn.imcompany.decorator.encrypt;
/**
* Created by tomyli on 2018/6/25.
* Github: https://github.com/peng051410
*/
public class ConverseEncryptDecorator extends EncryptDecorator {
public ConverseEncryptDecorator(Encryptor encrypt) {
super(encrypt);
}
@Override
public void encrypt() {
super.encrypt();
converseEncrypt();
}
public void converseEncrypt() {
System.out.println("逆向加密!");
}
}
上面的代码定义了两个具体的装饰器实体,在这两个装饰器类中,加密方法中都调用了父类的加密方法,然后调用了自己实现的加密方法,这样在先前加密的基础上又进行了一次加密。达到了双重加密的效果。让我们来进行一下测试:
package cn.imcompany.decorator.encrypt;
/**
* Created by tomyli on 2018/6/25.
* Github: https://github.com/peng051410
*/
public class EncryptDecoratorTest {
public static void main(String[] args) {
Encryptor encryptor = new ConcreteEncryptor();
//进行一次简单加密
Encryptor encryptDecorator = new SimpleEncryptDecorator(encryptor);
encryptDecorator.encrypt();
//对上一次加密进行二次加密(反转加密)
ConverseEncryptDecorator converseEncryptDecorator = new ConverseEncryptDecorator(encryptDecorator);
converseEncryptDecorator.encrypt();
}
}
在测试中先进行了一次简单的加密,又在第一次加密的基础上进行了二次加密,如果再想使用第三次加密,直接把二次加密的对象引用传入即可。这样可以形成很多种组合,可以满足很多加密的需求。
上面的加密类的类图如下:
总结
优点
- 针对抽象编程,装饰器可以使多个类的功能进行组合,比继承更加的灵活。
- 可以对一个对象进行多次的装饰,可以创造出具有强大功能的类。
- 具体的构建类与装饰器分隔,想要增加一个新功能时不需要修改原代码,符合开闭原则。
缺点
- 增加一个小的功能也需要增加一个类来实现,有些时候会有些浪费。
- 由于实现也多重装饰,在出现问题时对于定位问题要一层一层的来处理。