昨天跟大家提到装饰者设计模式,今天就来详细的对它进行了解吧。
首先我们要了解装饰者设计模式应用于什么场景,就说昨天的游戏案例,如果我们需要一个角色,不停的添加各种装备,比如说人物A叫盖伦,他不断的更新装备,那么这个时候我们就是动态的再给他添加装备,如果按照一般的逻辑,我们可能首先定义一个抽象的盖伦类,然后加一件装备创建一个对象来继承他,然后加具体的实现,这个时候如果有很多个种类,很多种搭配的话,就会发生类爆炸的问题。
此刻,装饰者设计模式就应运而生了。那么装饰者设计模式
意图: 动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更为灵活。该模式以对客户端透明的方式扩展对象的功能。
适用环境 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。 处理那些可以撤消的职责。 当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。
给大家分析一下装饰者设计模式的类图:
类图: Component(被装饰对象基类)
定义对象的接口,可以给这些对象动态增加职责;
ConcreteComponent(具体被装饰对象) 定义具体的对象,Decorator可以给它增加额外的职责;
Decorator(装饰者抽象类) 维护指向Component实例的引用,定义与Component一致的接口;
ConcreteDecorator(具体装饰者) 具体的装饰对象,给内部持有的具体被装饰对象增加具体的职责;
这样看起来可能大家没什么概念,那么我们直接上代码:
首先定义一个对象的接口,这样一方面利于扩展,另一方面可以使用多态来动态的给对象附加职责,此处接口我们定义为角色Role,并在接口中定义一个穿的装备的抽象方法:
//被装饰者的基类
interface Role {
String weapon(); //穿的装备
}
然后我们定义一个具体的被装饰对象GaiLun,并实现Role接口,简单实现,最基本的功能。
public class GaiLun implements Role{
public String weapon() {
return "盖伦";
}
}
之后就需要一个装饰者抽象类RoleDecorator 来实现Role接口,这里面需要封装一个被装饰者基类,也就是Role,然后在实现方法中调用role的实现,也就是在这里延迟到子类去实现来完成装饰者与被装饰者间的嵌套关系。
public class RoleDecorator implements Role {
private Role role;
public RoleDecorator(Role role){
this.role = role;
}
public String weapon() {
return role.weapon();
}
}
再接下来就是具体的装饰者对象了,此处我们定义一个RiYanKaiJia的具体类来实现对被装饰者的装饰:
public class RiYanKaiJia extends RoleDecorator{
public RiYanKaiJia(Role role) {
super(role);
}
//这里就实现对被装饰者的装饰衔接了
public String weapon() {
return super.weapon()+",日炎铠甲";
}
}
加入这里我们又添加一个狂徒铠甲,那么就直接再添加一个实现类即可:
public class KuangTuKaiJia extends RoleDecorator{
public KuangTuKaiJia(Role role) {
super(role);
}
public String weapon() {
return super.weapon()+",狂徒铠甲";
}
}
在测试类中具体的实现如下,这里我们就可以给他动态的添加装备了,IO流里面也就是使用到了这个模式。
public class Test {
public static void main(String[] args) {
Role role = new GaiLun();
KuangTuKaiJia kuangtu = new KuangTuKaiJia(role);
RiYanKaiJia riyan = new RiYanKaiJia(kuangtu);
System.out.println(riyan.weapon());
}
}
输出结果如下:
此处如果我们还需要继续添加装备就继续实现嵌套就行了,如果再有其他角色,比如赵信,也买防御装备的话,就可以重复使用这两件装备直接嵌套就可以了。
威哥说:
OO原则:动态地将责任附加到对象上。想要扩展功能,装饰者提供有别于继承的另一种选择。
要点: 1、继承属于扩展形式之一,但不见得是达到弹性设计的最佳方案。
2、在我们的设计中,应该允许行为可以被扩展,而不须修改现有的代码。
3、组合和委托可用于在运行时动态地加上新的行为。
4、除了继承,装饰者模式也可以让我们扩展行为。
5、装饰者模式意味着一群装饰者类,这些类用来包装具体组件。
6、装饰者类反映出被装饰的组件类型(实际上,他们具有相同的类型,都经过接口或继承实现)。
7、装饰者可以在被装饰者的行为前面与/或后面加上自己的行为,甚至将被装饰者的行为整个取代掉,而达到特定的目的。
8、你可以有无数个装饰者包装一个组件。
9、装饰者一般对组建的客户是透明的,除非客户程序依赖于组件的具体类型。