设计模式 - 装饰模式
实例
数据加密
假设一个数据加密的应用场景,可以对字符串进行加密,用户先使用最简单的加密算法对字符串进行加密,如果觉得不够,可以对加密后的结果使用MD5
、AES
、RSA
等加密算法进行二次加密
解决方案
Encrypt.java
/**
* @Description 加密
*/
public class Encrypt {
public String encrypt(String str) {
return str + " 常规加密";
}
}
AESEncrypt.java
/**
* @Description AES加密
*/
public class AESEncrypt extends Encrypt {
@Override
public String encrypt(String str) {
return super.encrypt(str) + " AES加密";
}
}
MD5Encrypt.java
/**
* @Description MD5加密
*/
public class MD5Encrypt extends Encrypt {
@Override
public String encrypt(String str) {
return super.encrypt(str) + " MD5加密";
}
}
RSAEncrypt.java
/**
* @Description RSA加密
*/
public class RSAEncrypt extends Encrypt {
@Override
public String encrypt(String str) {
return super.encrypt(str) + " RSA加密";
}
}
Test.java
/**
* @Description 测试类
*/
public class Test {
public static void main(String[] args) {
Encrypt encrypt = new Encrypt();
System.out.println(encrypt.encrypt("encrypt data"));
MD5Encrypt md5Encrypt = new MD5Encrypt();
System.out.println(md5Encrypt.encrypt("encrypt data"));
AESEncrypt aesEncrypt = new AESEncrypt();
System.out.println(aesEncrypt.encrypt("encrypt data"));
RSAEncrypt rsaEncrypt = new RSAEncrypt();
System.out.println(rsaEncrypt.encrypt("encrypt data"));
}
}
- 输出如下:
encrypt data 常规加密
encrypt data 常规加密 MD5加密
encrypt data 常规加密 AES加密
encrypt data 常规加密 RSA加密
- 类图如下:
需求变更
-
满足如上业务场景后,用户需求变更,需要进行3次或多次加密,可以看出,如上代码对于用户想要进行多次加密的行为无法实现,接下来引出装饰模式
-
装饰模式用于扩展系统功能,其可以在不改变一个对象本身功能的基础上给对象增加额外的新行为
装饰模式
概念
- 装饰模式(
Decorator Pattern
):动态地给一个对象增加一些额外的职责 - 装饰模式提供了比继承更有弹性的替代方案(扩展原有对象功能)
- 装饰模式是一种对象结构型模式
- 装饰模式结构图(来自刘伟老师技术博客)
- 装饰模式角色定义:
角色 | 名称 | 释义 |
---|---|---|
Component | 抽象构件 | 具体构件和抽象装饰类的共同父类,声明了在具体构件中实现的业务方法 |
ConcreteComponent | 具体构件 | 抽象构件类的子类,用于定义具体的构件对象,实现了在抽象构件中声明的方法,装饰器可以给它增加额外的职责(方法) |
Decorator | 抽象装饰类 | 抽象构件类的子类,用于给具体构件增加职责,但是具体职责在其子类中实现。它维护一个指向抽象构件对象的引用,通过该引用可以调用装饰之前构件对象的方法,并通过其子类扩展该方法,以达到装饰的目的 |
ConcreteDecorator | 具体装饰类 | 抽象装饰类的子类,负责向构件添加新的职责。每一个具体装饰类都定义了一些新的行为,它可以调用在抽象装饰类中定义的方法,并可以增加新的方法用以扩充对象的行为 |
- 装饰模式是一种用于替代继承的技术,它通过一种无需定义子类的方式来给对象动态增加职责,使用对象之间的关联关系取代类之间的继承关系
装饰模式解决方案
AEncrypt.java
/**
* @Description 抽象加密构建类
*/
public abstract class AEncrypt {
/**
* 加密
* @param str
* @return
*/
public abstract String encrypt(String str);
}
CommonEncrypt.java
/**
* @Description 常规加密具体构建类
*/
public class CommonEncrypt extends AEncrypt {
@Override
public String encrypt(String str) {
return str + " 常规加密";
}
}
EncryptDecorator.java
/**
* @Description 抽象构建装饰类
*/
public abstract class EncryptDecorator extends AEncrypt {
// TODO 维持一个对抽象构件对象的引用
private AEncrypt aEncrypt;
// TODO 注入一个抽象构件类型的对象
public EncryptDecorator(AEncrypt aEncrypt) {
this.aEncrypt = aEncrypt;
}
@Override
public String encrypt(String str) {
// TODO 调用原有业务方法
return aEncrypt.encrypt(str);
}
}
AESDecorator.java
/**
* @Description AES加密具体装饰类
*/
public class AESDecorator extends EncryptDecorator {
public AESDecorator(AEncrypt aEncrypt) {
super(aEncrypt);
}
@Override
public String encrypt(String str) {
// TODO 调用原有业务方法 + 扩展新功能
return super.encrypt(str) + " AES加密";
}
}
MD5Decorator.java
/**
* @Description MD5加密具体装饰类
*/
public class MD5Decorator extends EncryptDecorator {
public MD5Decorator(AEncrypt aEncrypt) {
super(aEncrypt);
}
@Override
public String encrypt(String str) {
// TODO 调用原有业务方法 + 扩展新功能
return super.encrypt(str) + " MD5加密";
}
}
RSADecorator.java
/**
* @Description RSA加密具体装饰类
*/
public class RSADecorator extends EncryptDecorator {
public RSADecorator(AEncrypt aEncrypt) {
super(aEncrypt);
}
@Override
public String encrypt(String str) {
// TODO 调用原有业务方法 + 扩展新功能
return super.encrypt(str) + " RSA加密";
}
}
Test.java
/**
* @Description 装饰模式测试类
*/
public class Test {
public static void main(String[] args) {
/**
* 常规加密
*/
AEncrypt aEncrypt = new CommonEncrypt();
System.out.println(aEncrypt.encrypt("encrypt data"));
/**
* MD5加密
*/
aEncrypt = new MD5Decorator(aEncrypt);
System.out.println(aEncrypt.encrypt("encrypt data"));
/**
* RSA加密
*/
aEncrypt = new RSADecorator(aEncrypt);
System.out.println(aEncrypt.encrypt("encrypt data"));
/**
* AES加密
*/
aEncrypt = new AESDecorator(aEncrypt);
System.out.println(aEncrypt.encrypt("encrypt data"));
}
}
- 输出如下:
encrypt data 常规加密
encrypt data 常规加密 MD5加密
encrypt data 常规加密 MD5加密 RSA加密
encrypt data 常规加密 MD5加密 RSA加密 AES加密
- 类图如下:
总结
- 优点
1.继承的有力补充,比继承灵活,不改变原有对象的情况下给一个对象扩展功能
2.通过使用不同装饰类以及这些装饰类的排列组合可以实现不同的效果
3.符合开闭原则
- 缺点
1.会出现更多的代码,更多的类,增加程序复杂性
2.动态装饰时,多层装饰时会更复杂
- 适用场景
1.扩展一个类的功能或给一个类添加附加职责
2.动态的给一个对象添加功能,这些功能可以再动态的撤销
- 装饰模式源代码
BufferedReader(java.io)、BufferedInputStream、BufferedOutputStream、Cache(Mybatis)