美文网首页
装饰者模式与组合模式

装饰者模式与组合模式

作者: 攻城老狮 | 来源:发表于2020-06-27 11:31 被阅读0次

    装饰者模式与组合模式

    参考教程:https://www.bilibili.com/video/BV1G4411c7N4
    代码实现 Github:https://github.com/yaokuku123/pattern


    装饰者模式

    1. 案例

    星巴克咖啡订单项目(咖啡馆):

    1. 咖啡种类/单品咖啡:Espresso(意大利浓咖啡)、ShortBlack、LongBlack(美式 咖啡)、Decaf(无因咖啡)。

    2. 调料:Milk、Soy(豆浆)、Chocolate。

    3. 要求在扩展新的咖啡种类时,具有良好的扩展性、改动方便、维护方便。

    4. 使用OO的来计算不同种类咖啡的费用: 客户可以点单品咖啡,也可以单品咖啡+调料组合。

    1. 传统方案1
    1-1592440957464.png
    • 分析

    这样设计,会有很多类,当我们增加一个单品咖啡,或者一个新的调料, 类的数量就会倍增,就会出现类爆炸。

    1. 传统方案2
    2-1592441082436.png
    • 分析

    方案2可以控制类的数量,不至于造成很多的类。但是在增加或者删除调料种类时,代码的维护量很大。

    1. 装饰者模式

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

    1. 代码实现
    3-1592441224442.png 4-1592441287867.png
    package com.yqj.pattern.decorator;
    //抽象类,Component
    abstract class Drink {
        private String desc;
        private float price = 0.0f;
    
        public String getDesc() {
            return desc;
        }
    
        public void setDesc(String desc) {
            this.desc = desc;
        }
    
        public float getPrice() {
            return price;
        }
    
        public void setPrice(float price) {
            this.price = price;
        }
    
        public abstract float cost();
    }
    //缓存层,抽取具体单品的共性特征
    class Coffee extends Drink {
    
        @Override
        public float cost() {
            return this.getPrice();
        }
    }
    //单品咖啡1
    class ShortBlack extends Coffee {
        public ShortBlack() {
            setDesc("ShortBlack");
            setPrice(5.0f);
        }
    }
    //单品咖啡2
    class LongBlack extends Coffee {
        public LongBlack() {
            setDesc("Decaf");
            setPrice(3.0f);
        }
    }
    //装饰类,Decorator。其中obj为聚合的被装饰对象
    class Decorator extends Drink {
    
        private Drink obj;
    
        public Decorator(Drink obj) {
            this.obj = obj;
        }
        //递归叠加计算价格
        @Override
        public float cost() {
            return super.getPrice() + obj.cost();
        }
    
        @Override
        public String getDesc() {
            return super.getDesc() + "&&" + obj.getDesc();
        }
    }
    //具体的装饰类
    class Chocolate extends Decorator {
    
        public Chocolate(Drink obj) {
            super(obj);
            setDesc("Chocolate");
            setPrice(2.0f);
        }
    }
    
    class Milk extends Decorator {
    
        public Milk(Drink obj) {
            super(obj);
            setDesc("Milk");
            setPrice(1.0f);
        }
    }
    
    public class Client {
        public static void main(String[] args) {
            Drink order = new LongBlack();
            System.out.println(order.getDesc() + " " + order.cost());
            order = new Milk(order);
            System.out.println(order.getDesc() + " " + order.cost());
            order = new Chocolate(order);
            System.out.println(order.getDesc() + " " + order.cost());
            order = new Chocolate(order);
            System.out.println(order.getDesc() + " " + order.cost());
        }
    }
    

    组合模式

    1. 案例

    编写程序展示一个学校院系结构:需求是这样,要在一个页面中展示出学校的院系 组成,一个学校有多个学院,一个学院有多个系。如图:

    5-1592443002566.png
    1. 传统方式
    6.png
    • 分析

      1. 将学院看做是学校的子类,系是学院的子类,这样实际上是站在组织大小来进行分层次的。

      2. 实际上我们的要求是 :在一个页面中展示出学校的院系组成,一个学校有多个 学院,一个学院有多个系, 因此这种方案,不能很好实现的管理的操作,比如 对学院、系的添加,删除,遍历等。

      3. 解决方案:把学校、院、系都看做是组织结构,他们之间没有继承的关系,而是 一个树形结构,可以更好的实现管理操作。 => 组合模式

    1. 组合模式

    解释:它创建了对象组的树形结构,将对象组合成树状结构以表示“整体-部分”的层次关系。组合模式使得用户对单个对象和组合对象的访问具有一致性,即:组合能让客户以一致的方式处理个别对象以及组合对象。

    运用:)组合模式解决这样的问题,当我们的要处理的对象可以生成一颗树形结构,而我们要对树上的节点和叶子进行操作时,它能够提供一致的方式,而不用考虑它是节点还是叶子

    1. 代码实现
    7.png
    package com.yqj.pattern.composite;
    
    import java.util.ArrayList;
    import java.util.List;
    
    abstract class OrganizationComponent {
        private String name;
    
        public OrganizationComponent(String name) {
            this.name = name;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public void add(OrganizationComponent organizationComponent) {
            throw new UnsupportedOperationException();
        }
    
        public void remove(OrganizationComponent organizationComponent) {
            throw new UnsupportedOperationException();
        }
    
        public abstract void print();
    }
    
    class University extends OrganizationComponent {
        private List<OrganizationComponent> colleges = new ArrayList<>();
    
        public University(String name) {
            super(name);
        }
    
    
        @Override
        public void add(OrganizationComponent organizationComponent) {
            colleges.add(organizationComponent);
        }
    
        @Override
        public void remove(OrganizationComponent organizationComponent) {
            colleges.remove(organizationComponent);
        }
    
        @Override
        public void print() {
            System.out.println("++++++++++"+this.getName()+"++++++++++");
            for (OrganizationComponent college : colleges) {
                college.print();
            }
        }
    }
    
    class College extends OrganizationComponent {
        private List<OrganizationComponent> departments = new ArrayList<>();
    
        public College(String name) {
            super(name);
        }
    
        @Override
        public void add(OrganizationComponent organizationComponent) {
            departments.add(organizationComponent);
        }
    
        @Override
        public void remove(OrganizationComponent organizationComponent) {
            departments.remove(organizationComponent);
        }
    
        @Override
        public void print() {
            System.out.println("++++++++++"+this.getName()+"++++++++++");
            for (OrganizationComponent department : departments) {
                department.print();
            }
        }
    }
    
    class Department extends OrganizationComponent{
    
        public Department(String name) {
            super(name);
        }
    
        @Override
        public void print() {
            System.out.println(this.getName());
        }
    }
    
    public class Client {
        public static void main(String[] args) {
            //从大到小创建对象
            //创建学校
            University university = new University("首师大");
            //创建学院
            College computerCollege = new College("计算机学院");
            College chemcialCollege = new College("化学学院");
            //创建系
            Department department1 = new Department("软件工程");
            Department department2 = new Department("计算机科学与技术");
            Department department3 = new Department("通讯工程");
            Department department4 = new Department("化学师范");
            Department department5 = new Department("应用化学");
            //将系加入各学院
            computerCollege.add(department1);
            computerCollege.add(department2);
            computerCollege.add(department3);
            chemcialCollege.add(department4);
            chemcialCollege.add(department5);
            //将学院加入学校
            university.add(computerCollege);
            university.add(chemcialCollege);
            //移除一个系
            chemcialCollege.remove(department4);
            //打印
            university.print();
    
        }
    }
    
    1. 小结
    • 简化客户端操作。客户端只需要面对一致的对象而不用考虑整体部分或者节点叶子 的问题。
    • 具有较强的扩展性。当我们要更改组合对象时,我们只需要调整内部的层次关系, 客户端不用做出任何改动。
    • 方便创建出复杂的层次结构。客户端不用理会组合里面的组成细节,容易添加节点 或者叶子从而创建出复杂的树形结构。
    • 需要遍历组织机构,或者处理的对象具有树形结构时, 非常适合使用组合模式。
    • 要求较高的抽象性,如果节点和叶子有很多差异性的话,比如很多方法和属性 都不一样,不适合使用组合模式。

    相关文章

      网友评论

          本文标题:装饰者模式与组合模式

          本文链接:https://www.haomeiwen.com/subject/oipmfktx.html