设计模式----装饰模式

1、装饰模式概要

装饰者模式(Decorator):动态地为一个对象添加一些额外的职责,若要扩展一个对象的功能,装饰者提供了比继承更有弹性的替代方案。

装饰模式结构图

  • 抽象构件类(Component):给出一个抽象的接口,用以规范准备接收附加责任的对象
  • 具体构件类(ConcreteComponent):定义一个具体的准备接受附加责任的类,其必须实现Component接口。
  • 装饰者类(Decorator):持有一个构件(Conponent)对象的实例,并定义一个和抽象构件一致的接口。
  • 具体装饰者类(Concrete Decoratator):定义给构件对象“贴上”附加责任。

装饰者模式具有的一些特征

​ 1,装饰者(decorator)和被装饰(扩展)的对象有着相同的超类(supertype)。

​ 2,我们可以用多个装饰者去装饰一个对象。

​ 3,我们可以用装饰过的对象替换代码中的原对象,而不会出问题(因为他们有相同的超类)。

​ 4,装饰者可以在委托(delegate,即调用被装饰的类的成员完成一些工作)被装饰者的行为完成之前或之后加上他自己的行为。

​ 5,一个对象能在任何时候被装饰,甚至是运行时。

简单来说:装饰模式即为动态的扩展,而不是修改

我们想象一个场景,你是一个卖鸡蛋饼的小贩,鸡蛋饼的原始组成是一个面饼一个鸡蛋,但是有些顾客相加油条(奇葩的想法),或者想加烤肠

在你编写类的时候,如果初始创建了一个鸡蛋饼类里面存在鸡蛋饼的价格,那么加油条的时候,这个类就无法使用了就不得不编写一个新的类

假设原始的鸡蛋饼类为这样

public class Waffle {

    private String name = "鸡蛋饼";
    private double cost = 3.5;


    public void Describe(){
        System.out.println("我是" + name);
    }

    public void Price(){
        System.out.println("价格是" + cost);
    }
}

有同学说,我可以继承鸡蛋饼这个类,编写一个加油条的方法

那么如果你添加的种类多的话,就会想下面这个图一样

造成类的爆炸

星巴克添加调料的图

还有同学说我可以在其中编写方法,来添加油条

public class Waffle {

    private String name = "鸡蛋饼";
    private double cost = 3.5;
    private double chinese_Donut = 1;


    public void Describe(){
        System.out.println("我是" + name);
        
    }

    public void Price(){
        System.out.println("价格是" + cost);
    }
    
    public void addDonut(){
        this.name = name + "加了油条";
        this.cost = cost + chinese_Donut;
    }
}

如果是这样的话,那么问题就来了,我添加油条是一个方法,添加烤肠又是一个方法,如果东西多了的话,这个类需要添加无尽个方法,而且如果有一天不卖油条了,我还得进来删除油条这个方法。

我们所希望达到的情况是动态的扩展,而不是无尽的修改源码

那么这时候引入装饰模式就很有必要了

2、装饰模式案例代码

抽象构建类(Component)

public abstract class Component {
    
    abstract void method();  // 抽象方法

}

具体构建类(Concrete Component)

public class ConcreteComponent extends Component{
    
    @Override
    public void method() {
        // 实现抽象方法
    }

}

装饰者类(Decorator)

public abstract class Decorator extends Component{

    public abstract void method();
    
}

具体装饰者类(Concrete Decoratator)

public class Concrete_Decoratator extends CondimentDecorator{

    Concrete_Decoratator concrete_Decoratator
    
    public Concrete_Decoratator(Concrete_Decoratator concrete_Decoratator){
        this.Concrete_Decoratator = concrete_Decoratator;
    }
    
    @Override
    public void method() {
        // 实现抽象方法
    }

}

3、案例代码

我们现在真的是一个卖鸡蛋饼的小贩,我们手里能添加的东西目前有三个,里脊肉、烤肠、培根

我们希望编写一个类,能够动态的计算出价格和名称

抽象构建类(Component)

public abstract class Pancake {

    public String describe = "我是一种煎饼,但我不知道我具体是谁";
    
    public abstract void money();
    
}

具体构建类(Concrete Component)

public class Waffle extends Pancake {

    public Waffle() {
        setDescribe("鸡蛋饼");
    }


    @Override
    public void money() {
        setCost(3.5);
        System.out.println(getCost());
    }
}

装饰者类(Decorator)

public abstract class Condiment extends Pancake {

    public abstract String getDescribe();

}

具体装饰者类(Concrete Decoratator)

烤肠类

public class Sausage extends Condiment {

    public Pancake pancake;

    public Sausage(Pancake pancake) {
        this.pancake = pancake;
    }

    @Override
    public String getDescribe() {
         return pancake.getDescribe() + ",烤肠";
    }

    @Override
    public double money() {
        return 2 + pancake.money();
    }
}

培根类

public class Baconic extends Condiment {

    private Pancake pancake;

    public Baconic(Pancake pancake) {
        this.pancake = pancake;
    }

    @Override
    public String getDescribe() {
        return pancake.getDescribe() + ",培根";
    }

    @Override
    public double money() {
        return 2 + pancake.money();
    }
}

里脊肉类

public class Tenderloin extends Condiment {

    public Pancake pancake;

    public Tenderloin(Pancake pancake) {
        this.pancake = pancake;
    }

    @Override
    public String getDescribe() {
        return pancake.getDescribe() + ",里脊肉";
    }

    @Override
    public double money() {
        return 3 + pancake.money();
    }
}

测试类

public class Main {

    public static void main(String[] args) {

       Pancake waffle = new Waffle();  //初始化鸡蛋饼

       waffle = new Tenderloin(waffle);  // 鸡蛋饼添加里脊肉
       waffle = new Baconic(waffle);     // 鸡蛋饼添加培根

        System.out.println(waffle.getDescribe());
        System.out.println(waffle.money());

    }
}

控制台输出

控制台输出

这样就完成了动态装饰,其中的原理还需要慢慢体会。尤其是多态这一块。

猜你喜欢

转载自blog.csdn.net/m0_37564531/article/details/88641595