装饰模式(Decorator)

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

@@@练习示例: 
奖金计算。

@@@示例代码:
\pattern\TempDB.java

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

package patern;

import java.util.HashMap;
import java.util.Map;

/**
 * 在内存中模拟数据库,准备点测试数据,好计算奖金
 */
public class TempDB {
    private TempDB() {
    }
    
    /**
     * 记录每个人的月度销售额,只用了人员,月份没有用
     */
    public static Map<String, Double> mapMonthSaleMoney = 
    	new HashMap<String, Double>();
    
    static {
    	// 填充测试数据
    	mapMonthSaleMoney.put("张三", 10000.0);
    	mapMonthSaleMoney.put("李四", 20000.0);
    	mapMonthSaleMoney.put("王五", 30000.0);
    }
}

\pattern\Component.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

package patern;

import java.util.Date;

/**
 * 计算奖金的组件接口
 */
public abstract class Component {
    /**
     * 计算某人在某段时间内的奖金,有些参数在演示中并不会使用
     * 但在实际业务实现上是会用的,为了表示这是个具体的业务方法,
     * 因此这些参数被保留了
     * @param user 被计算奖金的人员
     * @param begin 计算奖金的开始时间
     * @param end 计算奖金的结束时间
     * @return 某人在某段时间内的奖金
     */
	public abstract double calcPrize(String user, Date begin, Date end);
}

\pattern\ConcreteComponent.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

package patern;

import java.util.Date;

public class ConcreteComponent extends Component {
	@Override
	public double calcPrize(String user, Date begin, Date end) {
		// 只是一个默认的实现,默认没有奖金
		return 0;
	}
}

\pattern\Decorator.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

package patern;

import java.util.Date;

/**
 * 装饰器的接口,需要和被装饰的对象实现同样的接口
 */
public abstract class Decorator extends Component {
    /**
     * 持有被装饰的组件对象
     */
	protected Component c;
	
	/**
	 * 通过构造方法传入被装饰的对象
	 * @param c 被装饰的对象
	 */
	public Decorator(Component c) {
		this.c = c;
	}
	
	@Override
	public double calcPrize(String user, Date begin, Date end) {
		// 转调组件对象的方法
		return c.calcPrize(user, begin, end);
	}
}

\pattern\MonthPrizeDecorator.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

package patern;

import java.util.Date;

/**
 * 装饰器对象,计算当月业务奖金
 */
public class MonthPrizeDecorator extends Decorator {
	public MonthPrizeDecorator(Component c) {
		super(c);
	}
    
	@Override
	public double calcPrize(String user, Date begin, Date end) {
		// 1:先获取前面运算出来的奖金
		double price = super.calcPrize(user, begin, end);
		
		// 2: 然后计算当月业务奖金,按人员和时间去获取当月业务额,然后再乘以3%
		double monthPrice = TempDB.mapMonthSaleMoney.get(user) * 0.03;
		System.out.println(user + "当月业务奖金" + monthPrice);
		
		return price + monthPrice;
	}
}

\pattern\SumPrizeDecorator.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

package patern;

import java.util.Date;

/**
 * 装饰器对象,计算累计奖金
 */
public class SumPrizeDecorator extends Decorator {
	public SumPrizeDecorator(Component c) {
		super(c);
	}
    
	@Override
	public double calcPrize(String user, Date begin, Date end) {
		// 1:先获取前面运算出来的奖金
		double price = super.calcPrize(user, begin, end);
		
		// 2: 然后计算累计奖金,本来应按人员去获取累计的业务额,然后再乘以0.1%
		// 简单示意一下,假定大家的累计业务额都是1000000元
		double sumPrice = 1000000 * 0.001;
		System.out.println(user + "累计奖金" + sumPrice);
		
		return price + sumPrice;
	}
}

\pattern\GroupPrizeDecorator.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

package patern;

import java.util.Date;

/**
 * 装饰器对象,计算当月团队业务奖金
 */
public class GroupPrizeDecorator extends Decorator {
	public GroupPrizeDecorator(Component c) {
		super(c);
	}
    
	@Override
	public double calcPrize(String user, Date begin, Date end) {
		// 1:先获取前面运算出来的奖金
		double price = super.calcPrize(user, begin, end);
		
		// 2: 然后计算当月团队业务奖金,先计算出团队总的业务额,然后再乘以1%
		// 假设都是一个团队的
		double groupSale = 0.0;
		for (double d : TempDB.mapMonthSaleMoney.values()) {
			groupSale += d;
		}
		double groupPrice = groupSale * 0.01;
		System.out.println(user + "当月团队业务奖金" + groupPrice);
		
		return price + groupPrice;
	}
}

\user\Client.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

package user;

import patern.Component;
import patern.ConcreteComponent;
import patern.Decorator;
import patern.GroupPrizeDecorator;
import patern.MonthPrizeDecorator;
import patern.SumPrizeDecorator;

/**
 * 使用装饰模式的客户端
 */
public class Client {
	public static void main(String[] args) {
        // 先创建计算基本奖金的类,这也是被装饰的对象
		Component basePrize = new ConcreteComponent();
		
		// 然后对计算的基本奖金进行装饰,这里要组合各个装饰
		// 说明,各个装饰模式之间最好不要有先后顺序的限制
		// 也就是先装饰谁和后装饰谁都应该是一样的
		
		// 先组合普通业务人员的奖金计算
		Decorator monthPrize = new MonthPrizeDecorator(basePrize);
		Decorator sumPrize = new SumPrizeDecorator(monthPrize);
		
		// 注意,这里只需要使用最后组合好的对象调用业务方法即可,会依次调用回去
		// 日期对象没有用到,所以传null即可
		double zs = sumPrize.calcPrize("张三", null, null);
		System.out.println("==========张三应得奖金:" + zs);
		double ls = sumPrize.calcPrize("李四", null, null);
		System.out.println("==========李四应得奖金:" + ls);
		
		// 如果是业务经理,还需要计算团队奖金
		Decorator groupPrize = new GroupPrizeDecorator(sumPrize);
		double ww = groupPrize.calcPrize("王五", null, null);
		System.out.println("==========王五应得奖金:" + ww);
	}
}

-- 运行结果 --
张三当月业务奖金300.0
张三累计奖金1000.0
==========张三应得奖金:1300.0
李四当月业务奖金600.0
李四累计奖金1000.0
==========李四应得奖金:1600.0
王五当月业务奖金900.0
王五累计奖金1000.0
王五当月团队业务奖金600.0
==========王五应得奖金:2500.0

@@@模式的实现:
使用对象组合。

@@@模式的优点:
1) 比继承更灵活;
2) 更容易复用功能;
3) 简化高层定义;

@@@模式的缺点:
会产生很多细粒度对象。

@@@模式的本质:
动态组合。

@@@模式体现的设计原则:
NA


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值