每天学习一个设计模式-4.装饰模式

装饰模式的本质是:动态组合。

一、装饰模式的定义:

动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式比生成子类更为灵活。

装饰模式类图

二、应用场景

1)需要在不影响其他对象的情况下,以动态、透明的方式给对象添加职责,可以使用装饰模式,这几乎就是装饰模式的主要功能;
2)不适合使用子类来扩展的时候,可以考虑使用装饰模式。因为装饰模式是使用“对象组合”的方式。

三、装饰模式代码示例

假设在计算员工奖金时,普通员工有月度奖金、团队奖金,部门经理不仅同时拥有月度、团队奖金,还额外拥有经理奖金,下面用编码模拟实现:

1、奖金计算器抽象类

/**
 * 奖金计算器
 */
public abstract class PrizeCalculator {

    /**
     * 计算奖金方法
     */
    protected abstract double calPrize(String user);
}

2、奖金计算器实现类

public class ConcretePrizeCalculator extends PrizeCalculator {

    @Override
    protected double calPrize(String user) {

        // 默认奖金为0
        return 0;
    }
}

3、装饰器抽象类

public abstract class Decorator extends PrizeCalculator {

    private PrizeCalculator prizeCalculator;

    public Decorator(PrizeCalculator prizeCalculator) {
        this.prizeCalculator = prizeCalculator;
    }

    @Override
    protected double calPrize(String user) {
        return prizeCalculator.calPrize(user);
    }
}

4、月度奖金装饰器

/**
 * 月度奖金装饰器
 */
public class MonthPrizeDecorator extends Decorator{

    public MonthPrizeDecorator(PrizeCalculator prizeCalculator) {
        super(prizeCalculator);
    }

    @Override
    protected double calPrize(String user) {

        //  假设当月业务奖金计算出来为1000元
        double monthPrize = 1000;

        System.out.println(String.format("%s获取的月度奖金为%s",user,monthPrize));

        return super.calPrize(user) + monthPrize;
    }
}

5、团队奖金装饰器

/**
 * 团队奖金装饰器
 */
public class GroupPrizeDecorator extends Decorator {

    public GroupPrizeDecorator(PrizeCalculator prizeCalculator) {
        super(prizeCalculator);
    }

    @Override
    protected double calPrize(String user) {

        // 假设计算出来的团队奖金为 1500
        double groupPrize = 1500;

        System.out.println(String.format("%s获取的团队奖金为%s",user,groupPrize));

        return super.calPrize(user) + groupPrize;
    }
}

6、经理奖金装饰器

/**
 * 部门经理奖金
 */
public class ManagerPrizeDecorator extends Decorator{

    public ManagerPrizeDecorator(PrizeCalculator prizeCalculator) {
        super(prizeCalculator);
    }

    @Override
    protected double calPrize(String user) {

        // 假设部门经理计算出来的奖金为2000
        double managerPrize = 2000;

        System.out.println(String.format("%s获取的经理奖金为%s",user,managerPrize));

        return super.calPrize(user) + managerPrize;
    }
}

7、客户端类

public class Client {

    public static void main(String[] args) {

        PrizeCalculator prizeCalculator = new ConcretePrizeCalculator();

        // 假设张三是普通员工,享有月度奖金和团队奖金
        // 用月度奖金装饰器装饰奖金计算器
        Decorator monthPrize = new MonthPrizeDecorator(prizeCalculator);
        
        // 用团队奖金装饰器装饰月度奖金装饰器
        Decorator groupPrize = new GroupPrizeDecorator(monthPrize);
        final double prizeZs = groupPrize.calPrize("张三");
        System.out.println("张三奖金总和:" + prizeZs);

        System.out.println("--------------------------------");

        // 假设李四是部门经理,享有月度奖金、团队奖金和经理奖金三种
        // 用部门奖金装饰器装饰团队奖金装饰器
        Decorator managerPrize = new ManagerPrizeDecorator(groupPrize);
        final double prizeLs = managerPrize.calPrize("李四");
        System.out.println("李四的奖金总和:" + prizeLs);
    }
}

8、运行结果
运行结果

四、装饰模式的优缺点

优点:

1)比继承更灵活;
2)符合开闭原则。

缺点:

1)会产生很多细粒度的对象。

你可能感兴趣的:(每天学习一个设计模式-4.装饰模式)