设计模式-装饰者模式(Decorator Pattern)

装饰者模式

定义
在不改变原有对象的基础上,将功能附加到原有功能上,进行功能的扩展。
装饰者模式提供了比继承更有弹性的替代方案。

类型
结构型。

适用场景

  • 扩展一个类的功能或者给一个类添加附加职责。
  • 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
  • 需要动态地给一个对象增加功能,这些功能也可以动态地被撤销。

优点

  • 通过使用不同装饰类以及这些类的排列组合,可以实现不同的效果。
  • 符合开闭原则。
  • 装饰者模式和继承关系的目的都是要扩展原有对象的功能,但是装饰者模式可以提供比继承更多的灵活型。

缺点

  • 更多的代码,更多的类,增加程序的复杂性。
  • 动态装饰时、多层装饰时会使系统更复杂。
  • 越灵活也意味着更容易出错。

相关设计模式

  • 装饰者模式和代理模式: 装饰者模式关注的是对象功能的动态添加。而代理模式关注的是对对象的控制访问,对它的用户隐藏对象的具体信息。

  • 装饰者模式和适配器模式:装饰者模式和被装饰的类要实现同一个接口,或者装饰类是被装饰的类的子类。 适配器模式和被适配的类具有不同的接口。

例子
这里举煎饼的例子,大家吃煎饼一般会加东西吧,比如鸡蛋、香肠等。
首先看看由普通继承来实现这个例子。
Battercake类,煎饼类。

package com.kaven.design.pattern.structural.decorator;

public class Battercake {
    protected String getDesc(){
        return "煎饼";
    }
    protected int cost(){
        return 8;
    }
}

BattercakeWithEgg类,加鸡蛋的煎饼类,继承了Battercake类。

package com.kaven.design.pattern.structural.decorator;

public class BattercakeWithEgg extends Battercake {

    public String getDesc() {
        return super.getDesc()+" 加一个鸡蛋";
    }

    public int cost() {
        return super.cost()+1;
    }
}

BattercakeWithSausage类,加香肠的煎饼类,继承了Battercake类。

package com.kaven.design.pattern.structural.decorator;

public class BattercakeWithSausage extends BattercakeWithEgg {
    @Override
    public String getDesc() {
        return super.getDesc()+" 加一根香肠";
    }

    @Override
    public int cost() {
        return super.cost()+2;
    }
}

应用层代码:

package com.kaven.design.pattern.structural.decorator;

public class Test {
    public static void main(String[] args) {
        Battercake battercake = new Battercake();
        System.out.println(battercake.getDesc()+" 销售价格:"+battercake.cost());

        BattercakeWithEgg battercakeWithEgg = new BattercakeWithEgg();
        System.out.println(battercakeWithEgg.getDesc()+" 销售价格:"+battercakeWithEgg.cost());

        BattercakeWithSausage battercakeWithSausage = new BattercakeWithSausage();
        System.out.println(battercakeWithSausage.getDesc()+" 销售价格:"
                + battercakeWithSausage.cost());

    }
}

输出:

煎饼 销售价格:8
煎饼 加一个鸡蛋 销售价格:9
煎饼 加一个鸡蛋 加一根香肠 销售价格:11

如果我需要加两个鸡蛋、两根香肠的煎饼呢?
此时,我们就需要再实现一个类来满足需求,但是这样的需求多种多样,显然用普通继承的方法来实现这个例子并不好。

改进
ABattercake类,抽象煎饼类。

package com.kaven.design.pattern.structural.decorator.v2;

public abstract class ABattercake {
    protected abstract String getDesc();
    protected abstract int cost();
}

Battercake类,具体煎饼类,继承ABattercake类。

package com.kaven.design.pattern.structural.decorator.v2;

public class Battercake extends ABattercake {

    protected String getDesc() {
        return "煎饼";
    }

    protected int cost() {
        return 8;
    }
}

AbstractDecorator类,抽象装饰者类,继承ABattercake类。

package com.kaven.design.pattern.structural.decorator.v2;

//根据业务来判断抽象装饰者是否要定义成抽象类
public class AbstractDecorator extends ABattercake {
    private ABattercake aBattercake;

    public AbstractDecorator(ABattercake aBattercake) {
        this.aBattercake = aBattercake;
    }

    protected String getDesc() {
        return this.aBattercake.getDesc();
    }

    protected int cost() {
        return this.aBattercake.cost();
    }
}

EggDecorator类,实现加鸡蛋业务的具体装饰者,继承AbstractDecorator类。

package com.kaven.design.pattern.structural.decorator.v2;

public class EggDecorator extends AbstractDecorator {
    public EggDecorator(ABattercake aBattercake) {
        super(aBattercake);
    }

    @Override
    protected String getDesc() {
        return super.getDesc()+" 加一个鸡蛋";
    }

    @Override
    protected int cost() {
        return super.cost()+1;
    }
}

SausageDecorator类,实现加香肠业务的具体装饰者,继承AbstractDecorator类。

package com.kaven.design.pattern.structural.decorator.v2;

public class SausageDecorator extends AbstractDecorator{

    public SausageDecorator(ABattercake aBattercake) {
        super(aBattercake);
    }

    @Override
    protected String getDesc() {
        return super.getDesc()+" 加一根香肠";
    }

    @Override
    protected int cost() {
        return super.cost()+2;
    }
}

应用层代码:

package com.kaven.design.pattern.structural.decorator.v2;

public class Test {
    public static void main(String[] args) {
        ABattercake aBattercake;
        aBattercake = new Battercake();
        aBattercake = new EggDecorator(aBattercake);
        aBattercake = new EggDecorator(aBattercake);
        aBattercake = new SausageDecorator(aBattercake);

        System.out.println(aBattercake.getDesc()+" 销售价格:"+aBattercake.cost());
    }
}

输出:

煎饼 加一个鸡蛋 加一个鸡蛋 加一根香肠 销售价格:12

一个简单的装饰者模式例子就完成了,这种方法是不是比上一种方法更容易扩展,想加几个鸡蛋、几根香肠都可以,并不需要再添加类,如果煎饼还可以加培根,这里就只需要添加一个加培根业务的具体装饰者即可。

如果有说错的地方,请大家不吝赐教(记得留言哦~~~~)。

发布了258 篇原创文章 · 获赞 161 · 访问量 32万+

猜你喜欢

转载自blog.csdn.net/qq_37960603/article/details/104087989