类型:结构型模式
要点:装饰者与被装饰者拥有共同的超类,继承的目的是继承类型,而不是行为。
介绍
意图: 动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。
主要解决: 一般的,我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀。
何时使用: 在不想增加很多子类的情况下扩展类。
如何解决: 将具体功能职责划分,同时继承装饰者模式。
关键代码:
- Component 类充当抽象角色,不应该具体实现。
- 修饰类引用和继承 Component 类,具体扩展类重写父类方法。
应用实例:
- 孙悟空有 72 变,当他变成"庙宇"后,他的根本还是一只猴子,但是他又有了庙宇的功能。
- 不论一幅画有没有画框都可以挂在墙上,但是通常都是有画框的,并且实际上是画框被挂在墙上。在挂在墙上之前,画可以被蒙上玻璃,装到框子里;这时画、玻璃和画框形成了一个物体。
优点: 装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。
缺点: 多层装饰比较复杂。
使用场景:
- 扩展一个类的功能。
- 动态增加功能,动态撤销。
注意事项: 可代替继承。
代码
案例一:Human
- 被装饰者基类
/**
* 被装饰者基类
* @author luis
*/
public interface Human {
/**
* 回家
*/
void goHome();
/**
* 上班
*/
void goWork();
}
- 具体被装饰者
/**
* 定义被装饰者,被装饰者初始状态有些自己的装饰
*
* @author luis
*/
public class Person implements Human {
@Override
public void goHome() {
System.out.println("回家回家,干点什么好呢");
}
@Override
public void goWork() {
System.out.println("上班上班,干点什么好呢");
}
}
- 装饰者基类
/**
* 定义装饰者:实现最基本功能
* @author luis
*/
public abstract class MyDecorator implements Human {
private Human human;
public MyDecorator(Human human) {
this.human = human;
}
@Override
public void goHome() {
human.goHome();
}
@Override
public void goWork() {
human.goWork();
}
}
- 装饰者(对普通装饰者功能进行扩展)
/**
* 装饰者的功能越来越多
* @author luis
*/
public class MyDecoratorProOne extends MyDecorator {
public MyDecoratorProOne(Human human) {
super(human);
}
public void playGame() {
System.out.println("玩联盟!");
}
public void problem() {
System.out.println("项目出问题啦!");
}
@Override
public void goHome() {
super.goHome();
playGame();
}
@Override
public void goWork() {
super.goWork();
problem();
}
}
- 装饰者(对普通装饰者功能进行扩展)
/**
* 装饰者的功能越来越多
* @author luis
*/
public class MyDecoratorProTwo extends MyDecorator {
public MyDecoratorProTwo(Human human) {
super(human);
}
public void login() {
System.out.println("上号!");
}
public void fixBug() {
System.out.println("改bug!");
}
@Override
public void goHome() {
super.goHome();
login();
}
@Override
public void goWork() {
super.goWork();
fixBug();
}
}
- 测试
/**
* 测试类,看一下你就会发现,跟java的I/O操作有多么相似
*/
public class Test {
public static void main(String[] args) {
Human person = new Person();
MyDecorator decorator = new MyDecoratorProTwo(new MyDecoratorProOne(person));
// 方法执行过程: two->decorator->person
decorator.goHome();
decorator.goWork();
}
}
- 结果
回家回家,干点什么好呢
玩联盟!
上号!
上班上班,干点什么好呢
项目出问题啦!
改bug!
案例二:鸡腿堡
- 被修饰者基类
/**
* 汉堡基类(被装饰者,相当于上面的Human)
*
* @author luis
*/
public abstract class Humburger {
/**
* 名称
*/
protected String name;
public String getName() {
return name;
}
/**
* 获取价格
*
* @return
*/
public abstract double getPrice();
}
- 具体被修饰者
/**
* 鸡腿堡类(被装饰者的初始状态,有些自己的简单装饰,相当于上面的Person)
* @author luis
*/
public class ChickenHunburger extends Humburger {
public ChickenHunburger() {
this.name = "鸡腿堡";
}
/**
* 获取价格
*
* @return
*/
@Override
public double getPrice() {
return 7;
}
}
- 装饰者基类(实现基本功能)
/**
* 配料的基类:装饰器
* (装饰者,用来对汉堡进行多层装饰,每层装饰增加一些配料,相当于上面Decorator)
*/
public abstract class PeiLiao extends Humburger {
/**
* 获取名称
*
* @return
*/
@Override
public abstract String getName();
}
- 装饰者具体实现类(第一层)
/**
* 生菜:(装饰者的第一层,相当于上面的decorator_one)
*
* @author luis
*/
public class Shengcai extends PeiLiao {
private Humburger humburger;
public Shengcai(Humburger humburger) {
this.humburger = humburger;
}
/**
* 获取价格
*
* @return
*/
@Override
public double getPrice() {
return humburger.getPrice() + 2;
}
/**
* 获取名称
*
* @return
*/
@Override
public String getName() {
return humburger.getName() + " 加生菜";
}
}
- 装饰者具体实现类(第二层)
/**
* 辣椒:(装饰者的第二层,相当于上面的decorator_two)
* @author luis
*/
public class LaJiao extends PeiLiao {
private Humburger humburger;
public LaJiao(Humburger humburger) {
this.humburger = humburger;
}
/**
* 获取价格
*
* @return
*/
@Override
public double getPrice() {
return humburger.getPrice()+1.5;
}
/**
* 获取名称
*
* @return
*/
@Override
public String getName() {
return humburger.getName()+" 加辣椒";
}
}
- 测试
public static void main(String[] args) {
Humburger humburger = new ChickenHunburger();
PeiLiao shengcai = new Shengcai(humburger);
PeiLiao laJiao = new LaJiao(humburger);
PeiLiao ljsc = new LaJiao(shengcai);
PeiLiao sclj = new Shengcai(laJiao);
System.out.println(humburger.getName() + " 价钱:" + humburger.getPrice());
System.out.println(shengcai.getName() + " 价钱:" + shengcai.getPrice());
System.out.println(laJiao.getName() + " 价钱:" + laJiao.getPrice());
System.out.println(ljsc.getName() + " 价钱:" + ljsc.getPrice());
System.out.println(sclj.getName() + " 价钱:" + sclj.getPrice());
}
- 结果
鸡腿堡 价钱:7.0
鸡腿堡 加生菜 价钱:9.0
鸡腿堡 加辣椒 价钱:8.5
鸡腿堡 加生菜 加辣椒 价钱:10.5
鸡腿堡 加辣椒 加生菜 价钱:10.5