装饰模式(Decorator)

来源:互联网 发布:安装ubuntu到u盘 编辑:程序博客网 时间:2024/04/27 15:13
@@@模式定义:
动态地给一个对象添加一些额外的职责。
就增加功能来说,装饰模式比生成子类更为灵活。

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

@@@示例代码:
\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 {@Overridepublic 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;}@Overridepublic 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);}    @Overridepublic 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);}    @Overridepublic 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);}    @Overridepublic 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


原创粉丝点击