• 装饰者模式


    1 简介

      装饰者模式:动态的将新功能附加到对象上。在对象功能扩展方面,它比继承更有弹性,装饰者模式也体现了开闭原则(ocp)

     

    2 特点

      从角色上来说,可分为装饰者(装饰对象)和被装饰者

        1) 装饰对象和被装饰者有相同的接口。
             2) 装饰对象包含一个被装饰者的引用(reference)
             3) 装饰对象接受所有来自客户端的请求。它把这些请求转发给被装饰者。
             4) 装饰对象可以在转发这些请求以前或以后增加一些附加功能。这样就确保了在运行时,不用修改给定对象的结构就可以在外部增加附加的功能。在面向对象的设计中,通常是通过继承来实现对给定类的功能扩展

     

    3 示例

    3.1 需求

      有这么一个需求,有不同品种的咖啡,有不同的配料,咖啡和配料可以随意组合,算出他们的价格。要求,具有良好的扩展性,咖啡和配料的种类随时可以扩展

     

    3.2 设计

      1)一个抽象类Drink,抽象出咖啡和配料的公有部分:两个变量:价格和描述。一个获取价格方法:cost

      2)咖啡类继承Drink,实现cost方法

      3)配料类继承Drink,实现cost方法,并且在里面加了一个参数drink,用来放coffee

      这里的关键是咖啡和配料继承同一个父类,并且在配料里面增加了一个放Drink参数,这样每次创建配料就把coffee传进去,就获得了咖啡+配料

     

     

    3.3 代码

    3.3.1 Drink

    public abstract class Drink {
    
        Double price = 0.0;
    
        String desc = "";
    
        abstract Double cost();
    
        public Double getPrice() {
            return price;
        }
    
        public void setPrice(Double price) {
            this.price = price;
        }
    
        public String getDesc() {
            return desc;
        }
    
        public void setDesc(String desc) {
            this.desc = desc;
        }
    }

     

    3.3.2 Coffee

    public class Coffee extends Drink{
    
        @Override
        public Double cost() {
            return super.getPrice();
        }
    }

     

    3.3.3 BlackCoffee

    public class BlackCoffee extends Coffee {
    
        public BlackCoffee() {
            //初始化价格和描述
            setPrice(4.0);
            setDesc("黑咖啡");
        }
    }

     

    3.3.4 Cappuccino

    public class Cappuccino extends Coffee{
    
        public Cappuccino() {
    
            setPrice(6.0);
            setDesc("卡布奇洛");
    
        }
    }

     

    3.3.5 Seaoning

    public class Seasoning extends Drink{
    
        //把Drink对象放在调料的类那里,每次创建调料放入coffee
    
        public Drink drink;
    
        public Drink getDrink() {
            return drink;
        }
    
        public void setDrink(Drink drink) {
            this.drink = drink;
        }
    
    
        public Double cost() {
            return super.getPrice() + drink.cost();
        }
    
        public String getDesc() {
            return super.getDesc()+ "+" + drink.getDesc();
        }
    
        public Seasoning(Drink drink) {
            this.drink = drink;
        }
        
    }

     

    3.3.6 Milk

    public class Milk extends Seasoning {
        
        public Milk(Drink drink) {
            super(drink);
            setPrice(2.0);
            setDesc("牛奶");
        }
    }

     

    3.3.7 Sugar

    public class Sugar extends Seasoning{
    
        public Sugar(Drink drink) {
            super(drink);
            setPrice(1.0);
            setDesc("");
        }
    }

     

    3.3.8 测试

    public class DrinkMaker {
    
    
        public static void main(String[] args) {
    
            //单品黑咖啡
            Drink d = new BlackCoffee();
            System.out.println(d.cost());
            System.out.println(d.getDesc());
    
            //加牛奶
            d = new Milk(d);
            System.out.println(d.cost());
            System.out.println(d.getDesc());
    
            //加糖
            d = new Sugar(d);
            System.out.println(d.cost());
            System.out.println(d.getDesc());
        }
    
    }

    执行结果

    4.0
    黑咖啡
    6.0
    牛奶+黑咖啡
    7.0+牛奶+黑咖啡

     

    3.4 扩展

      增加一种配料,只需要继承Seaoning即可

      增加一种coffee,只需要继承Coffee即可

      cost方法不需要不改变

     

  • 相关阅读:
    C++中的关键概念:名字查找与继承
    调用哪个虚函数的问题
    二叉树基础知识
    赫夫曼树及其应用
    用MyEclipse搭建SSH框架 Struts Spring Hibernate
    数据库 事务的特性ACID
    网桥与交涣机
    Adobe Edge Animate 1.0 概述
    【官方】Adobe Edge Preview 3 初学者指南
    Adobe Edge , Flash 未来的方向?
  • 原文地址:https://www.cnblogs.com/jthr/p/16379601.html
Copyright © 2020-2023  润新知