【设计模式】结构型模式——装饰模式

一、定义

装饰模式是一种结构型设计模式, 允许你通过将对象放入包含行为的特殊封装对象中来为原对象绑定新的行为。

二、问题

假设你的公司要发奖金,一个人有基础奖金,而有的人还有业务增长奖金个人进步奖金,更高层的人(比如 经理)除了有个人的奖金外,还有团队累计奖金团队增长奖金 等等。
如果我们使用一个子类来分发这些奖金,那么我们子类的组合会很多很多
在这里插入图片描述

那么我真的要设计这么多类吗?

三、解决方案

装饰模式就很好的解决了这一点:
我们可以将简单的发奖金行为放在基础装饰类中, 但将所有其他奖金方法放入装饰中。
客户端代码必须将基础装饰类放入一系列自己所需的装饰中。 因此最后的对象将形成一个结构。
实际与客户端进行交互的对象将是最后一个进入栈中的装饰对象(即具体部件)。

四、实现

1、部件 Component
发放奖金接口
声明封装器和被封装对象的公用接口。

package com.atmae.decorator;

/**
 * @Author: Mae
 * @Date: 2022/4/2
 * @Time: 13:00
 * @Description:
 */
public interface Reward{
    
    
    /**
     * 发放奖金
     * @return 奖金
     */
    void sendReward();
}

2、具体部件 Concrete Component
具体部件 (Concrete Component) 类是被封装对象所属的类。 它定义了基础行为, 但装饰类可以改变这些行为。
(1) 普通职工

package com.atmae.decorator;

/**
 * @Author: Mae
 * @Date: 2022/4/2
 * @Time: 13:06
 * @Description:
 */
public class Staff implements Reward {
    
    

    String name;
    public Staff(String name) {
    
    
        this.name=name;
    }

    @Override
    public void sendReward() {
    
    
        System.out.println("普通职工"+this.name+"基础工资:"+5000d);
    }
}

(2)、经理

package com.atmae.decorator;

/**
 * @Author: Mae
 * @Date: 2022/4/2
 * @Time: 15:22
 * @Description:
 */
public class Manage implements Reward{
    
    

    String name;

    public Manage(String name) {
    
    
        this.name=name;
    }

    @Override
    public void sendReward() {
    
    
        System.out.println("经理"+this.name+"基础工资为"+10000d);
    }
}

3、基础装饰类(BaseDecorator)

基础装饰 (Base Decorator) 类拥有一个指向被封装对象的引用成员变量。 该变量的类型应当被声明为通用部件接口, 这样它就可以引用具体的部件和装饰。 装饰基类会将所有操作委派给被封装的对象(具体部件)。

package com.atmae.decorator;

/**
 * @Author: Mae
 * @Date: 2022/4/2
 * @Time: 13:04
 * @Description:
 */
public class RewardDecorator implements Reward {
    
    

    private Reward reward;

    public RewardDecorator() {
    
    
    }

    public RewardDecorator(Reward reward) {
    
    
        this.reward = reward;
    }

    @Override
    public void sendReward() {
    
    
        reward.sendReward();
    }
}

4、具体装饰类 (Concrete Decorators)
具体装饰类 (Concrete Decorators) 定义了可动态添加到部件的额外行为。 具体装饰类会重写装饰基类的方法, 并在调用父类方法之前或之后进行额外的行为。
(1)、个人增长工资

package com.atmae.decorator;

/**
 * @Author: Mae
 * @Date: 2022/4/2
 * @Time: 13:58
 * @Description:
 */
public class SelfAccumulationRewardDecorator extends RewardDecorator{
    
    


    public SelfAccumulationRewardDecorator(Reward reward) {
    
    
        super(reward);
    }

    public SelfAccumulationRewardDecorator() {
    
    
    }

    @Override
    public void sendReward() {
    
    
        super.sendReward();
        System.out.println("\t\t个人累计工资:"+3000d);
    }
}

(2)、个人积累工资

package com.atmae.decorator;

/**
 * @Author: Mae
 * @Date: 2022/4/2
 * @Time: 13:56
 * @Description:
 */
public class SelfIncreaseRewardDecorator extends RewardDecorator{
    
    

    public SelfIncreaseRewardDecorator(Reward reward) {
    
    
        super(reward);
    }

    public SelfIncreaseRewardDecorator() {
    
    
    }

    @Override
    public void sendReward() {
    
    
        super.sendReward();
        System.out.println("\t\t个人增长工资:"+2000d);
    }
}

(3)、团队增长工资

package com.atmae.decorator;

/**
 * @Author: Mae
 * @Date: 2022/4/2
 * @Time: 15:37
 * @Description:
 */
public class TeamIncreaseRewardDecorator extends RewardDecorator{
    
    
    public TeamIncreaseRewardDecorator() {
    
    
    }

    public TeamIncreaseRewardDecorator(Reward reward) {
    
    
        super(reward);
    }

    @Override
    public void sendReward() {
    
    
        super.sendReward();
        System.out.println("\t\t团队增长工资:"+4000d);
    }
}

(4)、团队积累工资

package com.atmae.decorator;

/**
 * @Author: Mae
 * @Date: 2022/4/2
 * @Time: 13:57
 * @Description:
 */
public class TeamAccumulationRewardDecorator extends RewardDecorator{
    
    
    public TeamAccumulationRewardDecorator(Reward reward) {
    
    
        super(reward);
    }

    public TeamAccumulationRewardDecorator() {
    
    
    }

    @Override
    public void sendReward() {
    
    
        super.sendReward();
        System.out.println("\t\t团队积累工资:"+6000d);
    }
}

5、客户端(Client)
客户端 (Client) 可以使用多层装饰来封装部件, 只要它能使用通用接口与所有对象互动即可。

package com.atmae.decorator;

import java.awt.*;

/**
 * @Author: Mae
 * @Date: 2022/4/2
 * @Time: 14:39
 * @Description:
 */
public class Client {
    
    
    public static void main(String[] args) {
    
    
        RewardDecorator rewardDecorator=new SelfIncreaseRewardDecorator(new SelfAccumulationRewardDecorator(new Staff("小王")));
        rewardDecorator.sendReward();
        RewardDecorator rewardDecorator1=new TeamAccumulationRewardDecorator(new SelfAccumulationRewardDecorator(new Manage("老刘")));
        rewardDecorator1.sendReward();
    }
}

在这里插入图片描述
运行展示:(普通职工小王)
在这里插入图片描述
即 基础装饰类的reward变量 是 SelfIncrease……,而 Seflncrease……的reward变量 是 SelfAccmu……,而SelfAccmu……的reward变量是Staff。

调用方法工资方法时,先调用的是基础装饰类的sentReward方法,而基础装饰类的sentReward方法是 用reward变量 调用sentReward方法,而reward变量又是SelfIncrease……所以 调用SelfIncrease……的sentReward方法,调用SelfIncrease……的sentReward方法,先调用父类的sentReward方法,父类中的reward变量而是 SelfAccmu……,所以调用SelfAccumu……的sentReward方法………………依此类推,其实就是一个递归调用
debug 自己看看吧
在这里插入图片描述

五、UML图

在这里插入图片描述

六、装饰模式应用场景

  • 在无需修改代码的情况下即可使用对象, 且希望在运行时为对象新增额外的行为, 可以使用装饰模式
  • 用继承来扩展对象行为的方案难以实现或者根本不可行, 你可以使用该模式。

七、总结

优点

  • 你无需创建新子类即可扩展对象的行为。
  • 你可以在运行时添加或删除对象的功能。
  • 你可以用多个装饰封装对象来组合几种行为。
  • 单一职责原则。 你可以将实现了许多不同行为的一个大类拆分为多个较小的类。

缺点

  • 在封装器栈中删除特定封装器比较困难。
  • 实现行为不受装饰栈顺序影响的装饰比较困难。
  • 各层的初始化配置代码看上去可能会很糟糕

八、与其他模式的关系

  • 策略模式
    装饰模式可让你更改对象的外表, 策略模式则让你能够改变其本质。
    装饰模式是递归调用,策略模式是一次调用。

猜你喜欢

转载自blog.csdn.net/weixin_51799151/article/details/123913250