装饰者模式:
允许向一个已经创建的对象添加新的功能,同时又不改变其结构。装饰者模式属于结构型模式,它是作为现有的类的一个包装。
这种模式创建了一个装饰器类,用来包装原有的类,并在保持原类方法完整性的前提下,提供了额外的功能。
一般的结构如下UML类图:
Component是一个抽象父类,ConcreteComponent是其具体子类,负责具体实现父类的方法;
Decorator是一个装饰器类,聚合了Component类,有Component类的属性,ConcreteDecoratorA和ConcreteDecoratorB分别为其装饰器具体实现类。
说完了抽象层面,我们来举个具体的例子来实现。
想必大家也玩过游戏,我们以游戏角色为例,结构如下:
Role为抽象类,仅仅定义相关的属性与抽象方法,这里我只定义了一个抽象方法data()调用toString方法:
public abstract class Role {
private String job;
private int attack;
private int defence;
public abstract void data();
//getter、setter方法,可快速扫过
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
public int getAttack() {
return attack;
}
public void setAttack(int attack) {
this.attack = attack;
}
public int getDefence() {
return defence;
}
public void setDefence(int defence) {
this.defence = defence;
}
@Override
public String toString() {
return "Role{" +
"job='" + job + '\'' +
", attack=" + attack +
", defence=" + defence +
'}';
}
}
具体实现类Fighter(战士),通过构造函数初始化面板属性:
public class Fighter extends Role {
@Override
public void data() {
System.out.println(super.toString());
}
public Fighter() {
setJob("战士");
setAttack(10);
setDefence(10);
}
}
同样的实现类Wizard(法师):
public class Wizard extends Role{
@Override
public void data() {
System.out.println(super.toString());
}
public Wizard() {
setJob("法师");
setAttack(15);
setDefence(5);
}
}
接下来是Decorator(装饰器)类,继承Role,并且把Role类的对象作为其私有属性,通过传入Role参数初始化:
public class Decorator extends Role {
private Role role = null;
public Decorator(Role role) {
this.role = role;
}
@Override
public void data() {
role.data();
}
}
接下来是装饰器类的具体实现类Sword(剑),构造器传入Role参数。
这里为了简单说明仅仅只是用一个构造器加简单的打印语句代表已添加了装饰。
public class Sword extends Decorator {
public Sword(Role role) {
super(role);
System.out.println("装备上了武器——剑,攻击力提升了10:");
role.setAttack(role.getAttack()+10);
super.data();
}
}
同样的实现类Shield(盾):
public class Shield extends Decorator {
public Shield(Role role) {
super(role);
System.out.println("装备上了防具——盾牌,防御力提升了10:");
role.setDefence(role.getDefence()+10);
super.data();
}
}
现在来看看最后如何实现装饰者模式的调用操作吧:
动态的添加新功能附加在原始的对象上面去,通过传入对象为参数:
public class Client {
public static void main(String[] args) {
//新建战士对象
//构造器里赋初始属性
Role fighter = new Fighter();
//显示面板属性
fighter.data();
//装配——剑
fighter = new Sword(fighter);
System.out.println();
//新建战士对象
//构造器里赋初始属性
Role wizard = new Wizard();
//显示面板属性
wizard.data();
//装配——盾牌
wizard = new Shield(wizard);
}
}
得到输出结果:
Role{job='战士', attack=10, defence=10}
装备上了武器——剑,攻击力提升了10:
Role{job='战士', attack=20, defence=10}
Role{job='法师', attack=15, defence=5}
装备上了防具——盾牌,防御力提升了10:
Role{job='法师', attack=15, defence=15}
总结
- 功能:动态的将新功能附加到对象上。在对象功能扩展方面,它比继承更有弹性,装饰者模式也体现了开闭原则(ocp)。
- 关键: 1、Component 类充当抽象角色,不应具体实现。 2、修饰者类引用和继承 Component 类,具体扩展类重写父类方法。