文档章节

一天一种设计模式之八-----组合模式

tongqu
 tongqu
发布于 2016/03/15 23:22
字数 1239
阅读 84
收藏 7

一.组合模式简介

  1. 组合模式属于结构型模式

  2. 将组合模式合成树形结构以表示“部分-整体” 的层次结构。“Composite”使得用户对单个对象和组合对象的使用具有一致性。

  3. 适用性:

    1. 你想表示对象的部分-整体层次结构。

    2. 你希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。

  4. 结构:

    1. Component 为组合中的对象声明接口。在适当情况下,实现所有类共有接口的缺省行为。声明一个接口用于访问和管理component的子组件。

    2. leaf 在组合中表示叶节点对象,叶节点没有子节点。

    3. composite 定义有子部件的那些不见的行为。存储子部件。在component接口中实现与子部件有关的操作。

    4. client接口操作组合不见的对象。

  5. 组合模式分为透明模式和安全模式

    1. 透明模式:在Component中声明所有用来管 理子对象的方法,如Add()方法,Remove()方法及GetChild()方法,所有实现Component接口的子类都具备这些方法,这使得 Component和子类具备一致的行为接口,使得对客户端无需区别树叶和树枝对象。

    2. 安全模式: 在透明模式基础上把Component中声明所有用来管理子对象的方法移到Composite中,在Composite实现子对象的管理方法,那么 Leaf就没有子对象管理方法,这使得Composite和Leaf的行为接口不一致,所以客户端在调用时要知道树叶和树枝对象存在。

  6. 组合模式符合开放封闭原则,迪米特法则。

  7. 组合模式优点

    1. 高层模块调用简单:一棵属性结构中所有节点都是component,局部和整体对调用者来说没有任何区别,也就是说,高层模块不必关心自己处理的是单个对象还是整个组合结构,简化了高层模块的代码。

    2. 节点自由增加:使用组合模式后,如果想增加一个树枝节点,树叶节点,只要找到它的父节点set进去就可以。对以后维护非常简单。

  8. 组合模式缺点

    1. 树枝和树叶的实现中直接使用了实现类,这在面向接口编程上是很不恰当的,与依赖倒置原则冲突。

    2. 通过继承来实现的结构型模式,一定要小心子类覆盖父类方法,因为这样可能导致整个结构的功能发生难以预知的变化。

  9. 应用场景:

    1. 维护一个树形菜单,文件系统等。

二.测试代码

1.下述代码是一种透明模式的组合模式

public class ZuhemoshiTest {
    public static void main(String[] args) {
        Employer employer=new ProjectManager("项目经理");
        Employer employer2=new Programer("程序员1");
        Employer employer3=new Programer("程序员2");
        employer.add(employer2);
        employer.add(employer3);
    }
}
abstract class Employer{
    private String name;
    public void setName(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public abstract void add(Employer employer);
    public abstract void delete(Employer employer);
    public List<Employer> employers;
    public void printInfo(){
        System.out.println(name);
    }
    public List<Employer> getEmployers(){
        return employers;
    }
    public  void displayTree(Employer root) {//递归遍历整个树。
        List<Employer> children = root.getEmployers();

        for (Employer employer : children) {
            System.out.println(employer.getName());
            if(employer.getEmployers()!=null){
                for(Employer employer2:employer.getEmployers()){
                    displayTree(employer2);
                }
            }
        }
    }
}
class Programer extends Employer{//相当于leaf
    public Programer(String name){
        setName(name);
        employers=null;//最低端的程序员,能雇佣的只有脑子T T
    }
    @Override
    public void add(Employer employer) {
    }

    @Override
    public void delete(Employer employer) {
    }
    
}
class ProjectManager extends Employer{
    public ProjectManager(String name){
        setName(name);
        employers=new ArrayList<Employer>();
    }
    
    @Override
    public void add(Employer employer) {
        employers.add(employer);
    }

    @Override
    public void delete(Employer employer) {
        employers.remove(employer);
    }
    
}

上述代码定义了一个树形结构,假如我们想定义一个employer的动作,只需要在父类中定义,全部子类重写或者直接继承即可。

2.安全模式测试代码

public class ZuhemoshiTest {
    public static void main(String[] args) {
        Manager manager=new ProjectManager("项目经理");
        Employer employer2=new Programer("程序员1");
        Employer employer3=new Programer("程序员2");
        manager.add(employer2);
        manager.add(employer3);
    }
}
class Employer{
    protected String name;
    public void setName(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
}
class Programer extends Employer{//相当于leaf
    public Programer(String name){
        setName(name);
    }    
}
abstract class Manager extends Employer{
    public abstract void add(Employer employer);
    public abstract void delete(Employer employer);
    public List<Employer> employers;
    public void printInfo(){
        System.out.println(name);
    }
    public List<Employer> getEmployers(){
        return employers;
    }
    public  void displayTree(Manager root) {
        List<Employer> children = root.getEmployers();

        for (Employer employer : children) {
            if(employer instanceof Manager){
                System.out.println(employer.getName());
                displayTree((Manager)employer);
            }else {
                System.out.println(employer.getName());
            }
        }
    }
}
class ProjectManager extends Manager{
    public ProjectManager(String name){
        setName(name);
        employers=new ArrayList<Employer>();
    }
    
    @Override
    public void add(Employer employer) {
        employers.add(employer);
    }

    @Override
    public void delete(Employer employer) {
        employers.remove(employer);
    }
    
}

3.为了应对组合模式没有实现面向接口编程,个人认为可以通过接口实现。核心代码如下,这个相关资料里没有提到过,不知道对不对。欢迎大神指正。

interface Employ{
    public List<Employ> employs=new ArrayList<Employ>();//接口中声明的变量是final的,表示变量地址不会改变
    void add(Employ employ);
    void remove(Employ employ);
}




















© 著作权归作者所有

tongqu
粉丝 38
博文 37
码字总数 26162
作品 0
海淀
私信 提问
设计模式已经陨落了?

你现在是坐在一个程序员旁边吗?如果是的话,那么在你读下面的段落之前,有一个简单的实验。让他们到一边去,问问他们两个问题并记录下答案。首先问他们“什么是设计模式?”然后再问“说出你...

oschina
2014/03/11
9.5K
69
【设计模式】简单工厂模式 Simple Factory Pattern

简单工厂模式Simple Factory Pattern【Simple Factory Pattern】是设计模式里最简单的一个模式,又叫静态工厂模式【Static Factory Pattern】,这个模式没有收录在GOF 23 个模式中,因为他非...

风之源
2018/07/19
0
0
JavaScript设计模式总结

之前看过《JavaScript设计模式与开发实践》这本书,对书中的设计模式和一些相关案例也有了一定的了解,同时把这些设计模式的应用对应在在一些其他的项目中,进行了一些整理,如下仅供参考: ...

jefferyE
03/26
0
0
JavaScript 中常见设计模式整理

开发中,我们或多或少地接触了设计模式,但是很多时候不知道自己使用了哪种设计模式或者说该使用何种设计模式。本文意在梳理常见设计模式的特点,从而对它们有比较清晰的认知。 JavaScript 中...

牧云云
2018/05/18
0
0
设计模式15——Template Method设计模式

Template Method模板方法设计模式定义一个操作中算法的骨架,将具体步骤的执行延迟到子类中实现。Java中的抽象类就是使用了模板方法设计模式。模板方法设计模式结构如下: 以文档处理为例,T...

小米米儿小
2014/01/24
209
0

没有更多内容

加载失败,请刷新页面

加载更多

一套基于SpringBoot+Vue+Shiro 前后端分离 开发的代码生成器

一、前言 最近花了一个月时间完成了一套基于Spring Boot+Vue+Shiro前后端分离的代码生成器,目前项目代码已基本完成 止步传统CRUD,进阶代码优化: 该项目可根据数据库字段动态生成 controll...

郑清
今天
7
0
javascript-十六进制随机颜色

<script> // 编写一个函数,获得一个十六进制的随机颜色的字符串(如#20CD4F) // function randomColor(){ // var r = random(0,255).toString(16); // var g = random(0,255).toString(16......

ACKo
今天
3
0
springBoot +mybatis 出现sql 语句在数据库可以查询到,但是赋值到实体类上就没有的情况?

1.不要老是反复查看自己是否写错了,为啥有的能出来有的出不来? 可以查看配置文件中是否配置全: 如果在application.yml 文件中是如下配置: mybatis: mapper-locations: classpath:mapp...

kuchawyz
今天
3
0
正则表达式

一、RegExp对象 进行验证和查找的API 1、创建对象: (1)用/创建(直接量):var reg=/正则/ig,表达式固定不变时使用 (2)用new创建:var reg=new RegExp(‘正则’,‘ig’),表达式需要...

wytao1995
今天
3
0
实战限流(guava的RateLimiter)

关于限流 常用的限流算法有漏桶算法和令牌桶算法,guava的RateLimiter使用的是令牌桶算法,也就是以固定的频率向桶中放入令牌,例如一秒钟10枚令牌,实际业务在每次响应请求之前都从桶中获取...

程序员欣宸
今天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部