什么是装饰器模式
官方定义:装饰器模式,是动态地给一个对象添加一些额外的职责的模式,就增加功能来说,装饰器模式比生成子类更为灵活。
装饰器模式主要用于对某种基类需要经常进行修改属性的场合,比如 功放 就是对 有效信号 的装饰(放大有效信号), 滤波器 就是对 噪声 的装饰(削减噪声)。
Java中的 IO流 就广泛使用了 装饰器模式 ,比如 BufferedInputStream 等,都是对底层的节点流进行装饰,来提高性能的例子。
装饰器模式的实现
装饰器模式主要有四个组成部分:
①component—抽象组件:基类接口,可以为对象动态地添加属性、职责;
②ConcreteComponen—具体组件:需要被装饰的对象,通过实现接口来定义,类似于具体的人;
③Decorator—抽象装饰类:通过实现抽象组件接口并通过外类来扩展Component的功能;
④ConcreteDecoratorX—具体装饰类:用于装饰的对象,类似于人的衣服。
这里举一个简单的例子:
我们定义人作为一个抽象接口,他具有获取身高体重等方法,这就是抽象组件了;
interface Person{
double getHeight();
double getWeight();
}
现在我们再通过接口实现一个具体的人,xiaoTang,这就是具体组件了;
class XiaoTang implements Person{
// 设置初始属性
private double height = 170;
private double weight = 60;
// 实现对应方法
public double getHeight(){
return this.height;
}
public double getWeight(){
return this.weight;
}
}
我们知道不同的习惯会影响一个人的身高和体重,那么我定义一个抽象装饰类,里面定义两个方法,分别对具体组件的身高和体重进行调用;
abstract class Habits implements Person{
// 丢入抽象接口,以方便实现混合
private Person person;
// 有参构造函数,必要的
public Habits(Person person){
this.person = person;
}
@Override
public double getHeight() {
return this.person.getHeight();
}
@Override
public double getWeight() {
return this.person.getWeight();
}
}
最后定义 饮食 和 运动 继承该抽象装饰类,重写对应方法来实现 饮食 和 运动 对具体的人的属性的改变。
class Sport extends Habits{
public Sport(Person person) {
super(person);
}
@Override
public double getHeight() {
return super.getHeight()*1.2;
}
@Override
public double getWeight() {
return super.getWeight()*1.05;
}
}
class Eat extends Habits{
public Eat(Person person) {
super(person);
}
@Override
public double getHeight() {
return super.getHeight()*1.05;
}
@Override
public double getWeight() {
return super.getWeight()*1.3;
}
}
最后是测试代码:
public static void main(String[] args) {
XiaoTang xiaoTang = new XiaoTang();
Habits eat = new Eat(xiaoTang);
Habits sport = new Sport(xiaoTang);
System.out.println("由于进食,身高变成了"+eat.getHeight()+"cm");
System.out.println("由于进食,体重变成了"+eat.getWeight()+"kg");
System.out.println("由于运动,身高变成了"+sport.getHeight()+"cm");
System.out.println("由于运动,体重变成了"+sport.getWeight()+"kg");
//当然我们还可以进行混合,将eat实例丢入sport构造器中
Habits fix = new Sport(eat);
System.out.println("由于进食和运动,身高变成了"+fix.getHeight()+"cm");
System.out.println("由于进食和运动,身高变成了"+fix.getWeight()+"kg");
}
通过装饰器设计模式,我们在需要频繁嵌套修改对象属性时,只需要新增加定义具体装饰类,然后嵌套构造,即可进行嵌套修改。
对于修改顺序有严格要求的场合,按照修改顺序进行嵌套构造即可,比如要求类A先修改具体组件属性,然后再是类B修改,则可以将具体组件对象放入类A构造器中得到类A实例,然后再将类A实例放入类B构造器中得到类B实例,类B实例中的对象属性即为顺序修改后的属性。