@@@模式定义:
动态地给一个对象添加一些额外的职责。
就增加功能来说,装饰模式比生成子类更为灵活。
@@@练习示例:
奖金计算。
@@@示例代码:
\pattern\TempDB.java
\pattern\Component.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
\pattern\ConcreteComponent.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
\pattern\Decorator.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
\pattern\MonthPrizeDecorator.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
\pattern\SumPrizeDecorator.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
\pattern\GroupPrizeDecorator.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
\user\Client.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- 运行结果 --
张三当月业务奖金300.0
张三累计奖金1000.0
==========张三应得奖金:1300.0
李四当月业务奖金600.0
李四累计奖金1000.0
==========李四应得奖金:1600.0
王五当月业务奖金900.0
王五累计奖金1000.0
王五当月团队业务奖金600.0
==========王五应得奖金:2500.0
@@@模式的实现:
使用对象组合。
@@@模式的优点:
1) 比继承更灵活;
2) 更容易复用功能;
3) 简化高层定义;
@@@模式的缺点:
会产生很多细粒度对象。
@@@模式的本质:
动态组合。
@@@模式体现的设计原则:
NA
动态地给一个对象添加一些额外的职责。
就增加功能来说,装饰模式比生成子类更为灵活。
@@@练习示例:
奖金计算。
@@@示例代码:
\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