设计模式之组合模式

定义

​ 组合模式又叫部分整体模式,组合多个对象形成树形结构以表示“整体-部分”的结构层次。

​ 组合模式对单个对象(叶子对象)和组合对象(组合对象)具有一致性,它将对象组织到树结构中,可以用来描述整体与部分的关系。同时它也模糊了简单元素(叶子对象)和复杂元素(容器对象)的概念,使得客户能够像处理简单元素一样来处理复杂元素,从而使客户程序能够与复杂元素的内部结构解耦。

​ 在使用组合模式中需要注意一点也是组合模式最关键的地方:叶子对象和组合对象实现相同的接口。这就是组合模式能够将叶子节点和对象节点进行一致处理的原因。

 模式结构

 

​ 组合模式主要包含如下几个角色:

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

2.Leaf:叶子对象。叶子结点没有子结点。

3.Composite:容器对象,定义有枝节点行为,用来存储子部件,在Component接口中实现与子部件有关操作,如增加(add)和删除(remove)等。

​ 从模式结构中我们看出了叶子节点和容器对象都实现Component接口,这也是能够将叶子对象和容器对象一致对待的关键所在。

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

 

思路分析和图解(类图)

 

创建一个抽象类OrganizationComponent

 大学College 学院University 系Department继承OrganizationComponent

Department是叶子节点,University 、Department是非叶子节点

代码实现:

package com.dongguo.composite;

/**
 * @author Dongguo
 * @date 2021/8/22 0022-14:58
 * @description:
 */
public abstract class OrganizationComponent {
    private String name; // 名字
    private String des; // 说明

    protected void add(OrganizationComponent organizationComponent) {
        //默认实现
        throw new UnsupportedOperationException();
    }

    protected void remove(OrganizationComponent organizationComponent) {
        //默认实现
        throw new UnsupportedOperationException();
    }

    //构造器
    public OrganizationComponent(String name, String des) {
        super();
        this.name = name;
        this.des = des;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDes() {
        return des;
    }

    public void setDes(String des) {
        this.des = des;
    }

    //方法print, 做成抽象的, 子类都需要实现
    protected abstract void print();
}
package com.dongguo.composite;

/**
 * @author Dongguo
 * @date 2021/8/22 0022-15:00
 * @description: 系
 */
public class Department extends OrganizationComponent {
    //没有集合
    public Department(String name, String des) {
        super(name, des);
    }

    //add , remove 就不用写了,因为他是叶子节点
    @Override
    public String getName() {

        return super.getName();
    }

    @Override
    public String getDes() {
        return super.getDes();
    }

    @Override
    protected void print() {
        System.out.println(getName());
    }
}
package com.dongguo.composite;

import java.util.ArrayList;
import java.util.List;

/**
 * @author Dongguo
 * @date 2021/8/22 0022-15:03
 * @description: 学院
 */
public class University extends OrganizationComponent {
    List<OrganizationComponent> organizationComponents = new ArrayList<OrganizationComponent>();

    // 构造器
    public University(String name, String des) {
        super(name, des);
    }

    // 重写add
    @Override
    protected void add(OrganizationComponent organizationComponent) {
        organizationComponents.add(organizationComponent);
    }

    // 重写remove
    @Override
    protected void remove(OrganizationComponent organizationComponent) {
        organizationComponents.remove(organizationComponent);
    }

    @Override
    public String getName() {
        return super.getName();
    }

    @Override
    public String getDes() {
        return super.getDes();
    }

    // print 方法,就是输出University 包含的学院
    @Override
    protected void print() {
        System.out.println("--------------" + getName() + "--------------");
        //遍历organizationComponents
        for (OrganizationComponent organizationComponent : organizationComponents) {
            organizationComponent.print();
        }
    }
}

package com.dongguo.composite;

import java.util.ArrayList;
import java.util.List;

/**
 * @author Dongguo
 * @date 2021/8/22 0022-14:58
 * @description: 大学
 */
public class College extends OrganizationComponent {
    //List 中存放的Department
    List<OrganizationComponent> organizationComponents = new ArrayList<OrganizationComponent>();
    // 构造器
    public College(String name, String des) {
        super(name, des);
    }
    // 重写add
    @Override
    protected void add(OrganizationComponent organizationComponent) {

// 将来实际业务中,Colleage 的add 和University add 不一定完全一样
        organizationComponents.add(organizationComponent);
    }
    // 重写remove
    @Override
    protected void remove(OrganizationComponent organizationComponent) {
        organizationComponents.remove(organizationComponent);
    }
    @Override
    public String getName() {
        return super.getName();
    }
    @Override
    public String getDes() {
        return super.getDes();
    }
    // print 方法,就是输出University 包含的学院
    @Override
    protected void print() {

        System.out.println("--------------" + getName() + "--------------");
        //遍历organizationComponents
        for (OrganizationComponent organizationComponent : organizationComponents) {
            organizationComponent.print();
        }
    }
}
package com.dongguo.composite;

/**
 * @author Dongguo
 * @date 2021/8/22 0022-15:02
 * @description:
 */
public class Client {
    public static void main(String[] args) {
        //从大到小创建对象学校
        OrganizationComponent university = new University("清华大学", " 中国顶级大学");
        //创建学院
        OrganizationComponent computerCollege = new College("计算机学院", " 计算机学院");
        OrganizationComponent infoEngineercollege = new College("信息工程学院", " 信息工程学院");
        //创建各个学院下面的系(专业)
        computerCollege.add(new Department("软件工程", " 软件工程不错"));
        computerCollege.add(new Department("网络工程", " 网络工程不错"));
        computerCollege.add(new Department("计算机科学与技术", " 计算机科学与技术是老牌的专业"));
        infoEngineercollege.add(new Department("通信工程", " 通信工程不好学"));
        infoEngineercollege.add(new Department("信息工程", " 信息工程好学"));
        //将学院加入到学校
        university.add(computerCollege);
        university.add(infoEngineercollege);

        university.print();
       // infoEngineercollege.print();
    }
}
运行结果:
--------------清华大学--------------
--------------计算机学院--------------
软件工程
网络工程
计算机科学与技术
--------------信息工程学院--------------
通信工程
信息工程

优点

​ 1、可以清楚地定义分层次的复杂对象,表示对象的全部或部分层次,使得增加新构件也更容易。

​ 2、客户端调用简单,客户端可以一致的使用组合结构或其中单个对象。

​ 3、定义了包含叶子对象和容器对象的类层次结构,叶子对象可以被组合成更复杂的容器对象,而这个容器对象又可以被组合,这样不断递归下去,可以形成复杂的树形结构。

​ 4、更容易在组合体内加入对象构件,客户端不必因为加入了新的对象构件而更改原有代码。

缺点

​ 1、使设计变得更加抽象,对象的业务规则如果很复杂,则实现组合模式具有很大挑战性,而且不是所有的方法都与叶子对象子类都有关联

 模式适用场景

​ 1、需要表示一个对象整体或部分层次,在具有整体和部分的层次结构中,希望通过一种方式忽略整体与部分的差异,可以一致地对待它们。

​ 2、让客户能够忽略不同对象层次的变化,客户端可以针对抽象构件编程,无须关心对象层次结构的细节。

模式总结

​ 1、 组合模式用于将多个对象组合成树形结构以表示“整体-部分”的结构层次。组合模式对单个对象(叶子对象)和组合对象(容器对象)的使用具有一致性。

​ 2、 组合对象的关键在于它定义了一个抽象构建类,它既可表示叶子对象,也可表示容器对象,客户仅仅需要针对这个抽象构建进行编程,无须知道他是叶子对象还是容器对象,都是一致对待。

​ 3、 组合模式虽然能够非常好地处理层次结构,也使得客户端程序变得简单,但是它也使得设计变得更加抽象,而且也很难对容器中的构件类型进行限制,这会导致在增加新的构件时会产生一些问题。

组合模式在JDK 集合的源码分析

package com.dongguo.composite;

import java.util.HashMap;
import java.util.Map;

/**
 * @author Dongguo
 * @date 2021/8/22 0022-15:27
 * @description:
 */
public class CompositeDemo {
    public static void main(String[] args) {
        Map<Integer,String> hashMap = new HashMap<>();
        hashMap.put(0,"张三");
        Map<Integer,String> map = new HashMap<>();
        map.put(1,"李四");
        map.put(2,"王五");
        hashMap.putAll(map);
        System.out.println(hashMap);
    }
}

1、HashMap
HashMap中有一个putAll方法,参数是一个Map,这就是一种组合模式的体现:

 

   public void putAll(Map<? extends K, ? extends V> m) {
        putMapEntries(m, true);
    }
    final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) {
        int s = m.size();
        if (s > 0) {
            if (table == null) { // pre-size
                float ft = ((float)s / loadFactor) + 1.0F;
                int t = ((ft < (float)MAXIMUM_CAPACITY) ?
                         (int)ft : MAXIMUM_CAPACITY);
                if (t > threshold)
                    threshold = tableSizeFor(t);
            }
            else if (s > threshold)
                resize();
            for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {
                K key = e.getKey();
                V value = e.getValue();
                putVal(hash(key), key, value, false, evict);
            }
        }
    }
    final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
        else {
            Node<K,V> e; K k;
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
            else if (p instanceof TreeNode)
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            else {
                for (int binCount = 0; ; ++binCount) {
                    if ((e = p.next) == null) {
                        p.next = newNode(hash, key, value, null);
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            treeifyBin(tab, hash);
                        break;
                    }
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
                    p = e;
                }
            }
            if (e != null) { // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                return oldValue;
            }
        }
        ++modCount;
        if (++size > threshold)
            resize();
        afterNodeInsertion(evict);
        return null;
    }
Map是一个抽象的构建相当于Component 
Node是Hashmap的静态内部类相当于叶子节点,没有put putall这些方法
HashMap是Map的具体实现子类 实现了相关方法put putall

另外还有ArrayList中的addAll方法也是一样。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

失业找工作中

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值