装饰器模式

装饰器模式(Decorator Pattern)

定义

也叫包装模式 (Wrapper Pattern)

是指在不改变原有对象的基础上,将功能附加到对象上,提供了比继承更有弹性的替代方案。

属于结构型模式。

适用场景

  1. 适用于扩展一个类的功能或给一个类添加附加职责。
  2. 动态的给一个对象添加功能,这些功能可以再动态的撤销。
  3. 需要增加由一些基本功能的排列组合而产生的非常大量的功能,使用继承关系将变得非常复杂。

标准示例

Component 是一个最顶层的抽象组件。

其他都是Component的子类。

ConcreteComponent 是一个具体的组件,是默认的标配。

Decorator 是一个抽象的装饰器,让用户可以对其扩展定制。

ConcreteDecoratorA、ConcreteDecoratorB 就是两个具体的装饰类。

上述类图中具体代码如下:
Component

java 复制代码
public abstract class Component {
    public abstract void operation();
}

Decorator

java 复制代码
public abstract class Decorator extends Component{
    //持有组件对象
    protected Component component;

    /**
     * 构造方法,传入组件对象
     * @param component
     */
    public Decorator(Component component){
        this.component = component;
    }
    public void operation() {
        //转发请求给组件对象,可以在转发前后执行一些附加动作
        component.operation();
    }
}

ConcreteComponent

java 复制代码
public class ConcreteComponent extends Component{

    public void operation() {
        System.out.println("默认标准输出");
    }
}

ConcreteDecoratorA

java 复制代码
public class ConcreteDecoratorA extends Decorator{

    public ConcreteDecoratorA(Component component) {
        super(component);
    }

    private void operationOne(){
        System.out.println("A ~ one ~");
    }
    private void operationTwo(){
        System.out.println("A ~ two ~");}

    @Override
    public void operation() {
        //调用父类方法,可以在调用前后执行一些附加动作
        operationOne();
        super.operation();
        operationTwo();
    }
}

ConcreteDecoratorB

java 复制代码
public class ConcreteDecoratorB extends Decorator{
    
    public ConcreteDecoratorB(Component component) {
        super(component);
    }

    private void operationOne(){
        System.out.println("B ~ one ~");
    }
    private void operationTwo(){
        System.out.println("B ~ two ~");}

    @Override
    public void operation() {
        //调用父类方法,可以在调用前后执行一些附加动作
        operationOne();
        super.operation();
        operationTwo();
    }
}

以上是相关类,Client中展示了使用方法:

java 复制代码
public class Client {
    public static void main(String[] args) {
    	//首先定义一个 "默认标准"
        Component c1 = new ConcreteComponent();
        //在默认基础上,包装上decoratorA的逻辑
        Decorator decoratorA = new ConcreteDecoratorA(c1);
        //执行包装过A的operation方法,输出见<1>
        decoratorA.operation();
        //在默认基础上,包装上B的逻辑
        Decorator decoratorB = new ConcreteDecoratorB(c1);
        //执行包装过B的operation方法,输出见<2>
        decoratorB.operation();
        //在B的基础上(B是基于默认标准的),包装上A的逻辑
        Decorator decoratorAB = new ConcreteDecoratorA(decoratorB);
        //执行A(B(c1))的operation方法,输出见<3>
        decoratorAB.operation();
    }
}

Client main方法的输出:

输出<1>:A包裹c1

A ~ one ~

默认标准输出

A ~ two ~

输出<2>:B包裹c1

B ~ one ~

默认标准输出

B ~ two ~

输出<3>:B包裹c1,A包裹B

A ~ one ~

B ~ one ~

默认标准输出

B ~ two ~

A ~ two ~


装饰器模式可以达到上述层层装饰的效果,可以在不改变默认标准实现的前提下,通过层层包裹逻辑,增加其功能。

下面再举个实际场景的例子。

电商平台购物时,我们总会看到一些商品这样的销售策略,基础版一个价格,在基础版上叠加更多的功能/配置,并通过赠送的辅助产品不同,设置成不同的套餐,每个套餐价格也各异,丰俭由人。

我们以笔记本电脑为例:

基础版为:一部笔记本电脑,3699元

超值版为:一部笔记本电脑+高端电脑包+品牌鼠标,3999元

豪华版为:一部笔记本电脑+高端电脑包+品牌鼠标+外接键盘+笔记本支架+USB扩展坞,4299元

我们有这样几个类:

INoteBookPackage 笔记本套餐抽象类;(相当于 Component )

BasicPackage,基础套餐(相当于 ConcreteComponent )

SuperValuePackageDecorator,超值套餐;(相当于ConcreteDecoratorA )

LuxuryPackageDecorator,豪华套餐;(相当于ConcreteDecoratorB )

Decorator,装饰器

具体代码如下:
INoteBookPackage

java 复制代码
public abstract class INoteBookPackage {
    protected abstract String getConfigMsg();
    protected abstract int getConfigPrice();
}

BasicPackage

java 复制代码
public class BasicPackage extends INoteBookPackage{
    public String getConfigMsg() {
        return "一台笔记本";
    }

    public int getConfigPrice() {
        return 3699;
    }
}

Decorator

java 复制代码
public abstract class Decorator extends INoteBookPackage{

    private INoteBookPackage noteBookPackage;

    public Decorator(INoteBookPackage noteBookPackage){
        this.noteBookPackage = noteBookPackage;
    }

    protected String getConfigMsg() {
        return noteBookPackage.getConfigMsg();
    }

    protected int getConfigPrice() {
        return noteBookPackage.getConfigPrice();
    }
}

SuperValuePackageDecorator

java 复制代码
public class SuperValuePackageDecorator extends Decorator{
    public SuperValuePackageDecorator(INoteBookPackage noteBookPackage) {
        super(noteBookPackage);
    }
    @Override
    protected String getConfigMsg() {
        return super.getConfigMsg()+"+高端电脑包+品牌鼠标";
    }
    @Override
    protected int getConfigPrice() {
        return super.getConfigPrice()+300;
    }
}

LuxuryPackageDecorator

java 复制代码
public class LuxuryPackageDecorator extends Decorator{
    public LuxuryPackageDecorator(INoteBookPackage noteBookPackage) {
        super(noteBookPackage);
    }
    @Override
    protected String getConfigMsg() {
        return super.getConfigMsg()+"+外接键盘+笔记本支架+USB扩展坞";
    }
    @Override
    protected int getConfigPrice() {
        return super.getConfigPrice()+300;
    }
}

Client

java 复制代码
public class Client {
    public static void main(String[] args) {
        INoteBookPackage noteBookPackage = new BasicPackage();
        System.out.println("默认标配:"+noteBookPackage.getConfigMsg()+" 价格:" + noteBookPackage.getConfigPrice());

        Decorator superValuePackage = new SuperValuePackageDecorator(noteBookPackage);
        System.out.println("超值套餐:"+superValuePackage.getConfigMsg()+" 价格:"+superValuePackage.getConfigPrice());

        Decorator luxuryPackage = new LuxuryPackageDecorator(superValuePackage);
        System.out.println("豪华套餐:"+luxuryPackage.getConfigMsg()+" 价格:"+luxuryPackage.getConfigPrice());
    }
}

Client 的main执行结果为:

shell 复制代码
默认标配:一台笔记本 价格:3699
超值套餐:一台笔记本+高端电脑包+品牌鼠标 价格:3999
豪华套餐:一台笔记本+高端电脑包+品牌鼠标+外接键盘+笔记本支架+USB扩展坞 价格:4299

以上为本文全部内容,感谢阅读。

相关推荐
乌啼霜满天249几秒前
JDBC编程---Java
java·开发语言·sql
大白要努力!11 分钟前
Android opencv使用Core.hconcat 进行图像拼接
android·opencv
色空大师13 分钟前
23种设计模式
java·开发语言·设计模式
闲人一枚(学习中)14 分钟前
设计模式-创建型-建造者模式
java·设计模式·建造者模式
2202_7544215431 分钟前
生成MPSOC以及ZYNQ的启动文件BOOT.BIN的小软件
java·linux·开发语言
蓝染-惣右介34 分钟前
【MyBatisPlus·最新教程】包含多个改造案例,常用注解、条件构造器、代码生成、静态工具、类型处理器、分页插件、自动填充字段
java·数据库·tomcat·mybatis
小林想被监督学习35 分钟前
idea怎么打开两个窗口,运行两个项目
java·ide·intellij-idea
HoneyMoose37 分钟前
IDEA 2024.3 版本更新主要功能介绍
java·ide·intellij-idea
我只会发热38 分钟前
Java SE 与 Java EE:基础与进阶的探索之旅
java·开发语言·java-ee
是老余39 分钟前
本地可运行,jar包运行错误【解决实例】:通过IDEA的maven package打包多模块项目
java·maven·intellij-idea·jar