设计模式《组合模式》

引言

  上一节说了中介者模式,这话咱们说说组合模式。这个模式主要是用来表示具有“整体—部分”关系的层次结构。

示例地址

  Demo

类图

image

定义

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

使用场景

  表示对象的部分-整体层次结构时。
  从一个整体中能够独立出部分模块或功能的场景。

背景故事

  我们去服装市场,看看服装的分类,服装下面有男装、女装。男装下面有包含短裤、衬衫,女装下面包含裙子、小脚裤。按照我们一半的写法,可以这样写。

一般写法

1. 子节点
/**
 * 子节点
 *
 * @author 512573717@qq.com
 * @created 2018/8/2  上午11:43.
 */
public class ChildNode {

    private String nodeName;

    public ChildNode(String nodeName) {
        this.nodeName = nodeName;
    }

    public void getNickname(String pre) {
        System.out.println(pre + "-" + nodeName);

    }
}
2. 父节点
/**
 * 父节点
 *
 * @author 512573717@qq.com
 * @created 2018/8/2  下午2:00.
 */
public class ParentNode {

    private List<ChildNode> mLeafList = new ArrayList<>();

    private List<ParentNode> mParentList = new ArrayList<>();

    private String nodeName;

    public ParentNode(String nodeName) {
        this.nodeName = nodeName;
    }

    public void addParent(ParentNode parent) {
        mParentList.add(parent);
    }

    public void addLeaf(ChildNode leaf) {
        mLeafList.add(leaf);
    }

    public void getNickname(String pre) {
        System.out.println(pre + nodeName);
        //然后添加一个空格,表示向后缩进一个空格,输出自己包含的叶子对象
        pre += " ";
        for (ChildNode leaf : mLeafList) {
            leaf.getNickname(pre);
        }
        //输出当前对象的子对象了
        for (ParentNode c : mParentList) {
            //递归输出每个子对象
            c.getNickname(pre);
        }
    }
}
3. Client
  //定义所有的组合对象
  ParentNode root = new ParentNode("服装");
  ParentNode c1 = new ParentNode("男装");
  ParentNode c2 = new ParentNode("女装");

  //定义所有的叶子对象
  ChildNode leaf1 = new ChildNode("衬衣");
  ChildNode leaf2 = new ChildNode("夹克");
  ChildNode leaf3 = new ChildNode("裙子");
  ChildNode leaf4 = new ChildNode("套装");

  //按照树的结构来组合组合对象和叶子对象
  root.addParent(c1);
  root.addParent(c2);

  c1.addLeaf(leaf1);
  c1.addLeaf(leaf2);
  c2.addLeaf(leaf3);
  c2.addLeaf(leaf4);

  //调用根对象的输出功能来输出整棵树
  root.getNickname("");
4. Result
 服装
  男装
   -衬衣
   -夹克
  女装
   -裙子
   -套装
5. 存在缺点

  需要知道那个是子节点,那个是父节点。然后按照对应的节点去添加。区别对待组合对象和叶子对象,不仅让程序变得复杂,还对功能的扩展也带来不便。

组合模式实现

1. 抽象节点类
/**
 * 节点抽象类
 *
 * @author 512573717@qq.com
 * @created 2018/8/2  下午2:17.
 */
public abstract class Node {
    //节点名字
    protected String nodeName;

    public Node(String nodeName) {
        this.nodeName = nodeName;
    }

    public void setNodeName(String nodeName) {
        this.nodeName = nodeName;
    }

    // 打印节点名字
    public abstract void getNodeName(String prefix);

    //添加节点
    public void addNode(Node node) {

    }

    //删除节点
    public void removeNode(Node node) {

    }

    //查找节点
    public void getIndexNode(int index) {

    }

}
2. 定义父节点
/**
 * 父节点
 *
 * @author 512573717@qq.com
 * @created 2018/8/2  下午2:43.
 */
public class ParentNode extends Node {

    private List<Node> mParents = null;

    public ParentNode(String nodeName) {
        super(nodeName);
    }

    @Override
    public void getNodeName(String prefix) {

        System.out.println(prefix+nodeName);

        if (this.mParents != null) {
            prefix +=" ";
            for (Node c : mParents) {
                //递归输出每个子对象
                c.getNodeName(prefix);
            }
        }
    }

    @Override
    public void addNode(Node parent) {
        if (mParents == null) {
            mParents = new ArrayList<Node>();
        }
        mParents.add(parent);
    }
}
3. 定义子节点
/**
 * 子节点
 *
 * @author 512573717@qq.com
 * @created 2018/8/2  下午2:25.
 */
public class ChildNode extends Node {

    public ChildNode(String nodeName) {
        super(nodeName);
    }

    @Override
    public void getNodeName(String prefix) {
        System.out.println(prefix+"-"+ nodeName);
    }
}
4. Client
  Node root = new ParentNode("服装");
  Node c1 = new ParentNode("男装");
  Node c2 = new ParentNode("女装");

  //定义所有的叶子对象
  Node leaf1 = new ChildNode("衬衣");
  Node leaf2 = new ChildNode("夹克");
  Node leaf3 = new ChildNode("裙子");
  Node leaf4 = new ChildNode("套装");

  //按照树的结构来组合组合对象和叶子对象
  root.addNode(c1);
  root.addNode(c2);
  c1.addNode(leaf1);
  c1.addNode(leaf2);
  c2.addNode(leaf3);
  c2.addNode(leaf4);
  //调用根对象的输出功能来输出整棵树
  root.getNodeName("");

组合模式的2种实现方式

安全性实现

  如果把管理子组件的操作定义在ParentNode中,那么客户在使用叶子对象的时候,就不会发生使用添加子组件或是删除子组件的操作了,因为压根就没有这样的功能,这种实现方式是安全的。

透明性实现

  如果把管理子组件的操作定义在Node中,那么客户端只需要面对Node,而无需关心具体的组件类型,这种实现方式就是透明性的实现。上面的示例就是透明性的。

总结

  通过使用组合模式,把一个“部分-整体”的层次结构表示成了对象树的结构,这样一来,客户端就无需再区分操作的是组合对象还是叶子对象了,对于客户端而言,操作的都是组件对象。

参考链接

  组合模式

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,761评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,953评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,998评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,248评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,130评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,145评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,550评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,236评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,510评论 1 291
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,601评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,376评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,247评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,613评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,911评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,191评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,532评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,739评论 2 335

推荐阅读更多精彩内容