• 尚硅谷设计模式学习(十)组合模式


    以学校院系展示引出组合模式

    在一个页面中展示出学校的院系组成,一个学校有多个学院, 一个学院有多个系。如图:

    传统方案解决学校院系展示(类图) 

    问题分析

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

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

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

    一、组合模式

    1、基本介绍

    组合模式,又称为部分与整体模式,将对象组合成树状结构以表示“整体-部分”的层次关系。

    组合模式依据树形结构来组合对象,用来表示部分以及整体层次,属于结构型模式

    组合模式使得用户对单个对象和组合对象的访问具有一致性,(即组合能让客户端以一致的方式处理个别对象以及组合对象)

     

    • Component:这是组合中对象声明接口,在适当情况下,实现所有类共有的接口默认行为,用于访问和管理 Component 子部件,Component可以是抽象类或者接口
    • Leaf:在组合中表示叶子节点,叶子节点没有子节点
    • Composite:非叶子节点,用于存储子部件,在  Component接口中实现子部件的相关操作,比如增加(add), 删除。 

    2、代码实现

    组织管理的抽象类

    1. public abstract class OrganizationComponent {
    2. private String name;
    3. //描述
    4. private String description;
    5. //初始化
    6. public OrganizationComponent(String name,String description){
    7. this.name = name;
    8. this.description = description;
    9. }
    10. public String getName() {
    11. return name;
    12. }
    13. public void setName(String name) {
    14. this.name = name;
    15. }
    16. public String getDescription() {
    17. return description;
    18. }
    19. public void setDescription(String description) {
    20. this.description = description;
    21. }
    22. //输出打印方法; 大学,学院,院系都需要的;作为抽象方法;
    23. protected abstract void print();
    24. //由于叶子节点可能不需要某些方法,所以就没用抽象方法,比如院系就不需要实现
    25. //添加方法;
    26. protected void add(OrganizationComponent organizationComponent){
    27. throw new UnsupportedOperationException();
    28. }
    29. //删除方法;
    30. protected void remove(OrganizationComponent organizationComponent){
    31. throw new UnsupportedOperationException();
    32. }
    33. }

    大学类:作为 Composite 管理College(学院) 

    1. public class University extends OrganizationComponent{
    2. //这里存放的是学院;
    3. List organizationComponents = new ArrayList();
    4. public University(String name, String description) {
    5. super(name, description);
    6. }
    7. //添加方法
    8. @Override
    9. protected void add(OrganizationComponent organizationComponent) {
    10. organizationComponents.add(organizationComponent);
    11. }
    12. //删除方法
    13. @Override
    14. protected void remove(OrganizationComponent organizationComponent) {
    15. organizationComponents.remove(organizationComponent);
    16. }
    17. @Override
    18. protected void print() {
    19. System.out.println("-------------" + getName() + "------------------------");
    20. for (OrganizationComponent organizationComponent : organizationComponents) {
    21. organizationComponent.print();
    22. }
    23. }
    24. }

    学院类:管理院系 

    1. public class College extends OrganizationComponent{
    2. List organizationComponents = new ArrayList();
    3. public College(String name, String description) {
    4. super(name, description);
    5. }
    6. //添加方法
    7. @Override
    8. protected void add(OrganizationComponent organizationComponent) {
    9. organizationComponents.add(organizationComponent);
    10. }
    11. //删除方法
    12. @Override
    13. protected void remove(OrganizationComponent organizationComponent) {
    14. organizationComponents.remove(organizationComponent);
    15. }
    16. @Override
    17. protected void print() {
    18. System.out.println("-------------" + getName() + "------------------------");
    19. for (OrganizationComponent organizationComponent : organizationComponents) {
    20. organizationComponent.print();
    21. }
    22. }
    23. }

     院系类

    1. public class Department extends OrganizationComponent{
    2. public Department(String name, String description) {
    3. super(name, description);
    4. }
    5. @Override
    6. protected void print() {
    7. System.out.println(getName() + " " + getDescription());
    8. }
    9. }

     测试使用

    1. public class Client {
    2. public static void main(String[] args) {
    3. OrganizationComponent university = new University("大学", "大学");
    4. OrganizationComponent computerCollege = new College("计算机学院", "计算机");
    5. OrganizationComponent messageCollege = new College("信息与工程学院","信息与工程");
    6. computerCollege.add(new Department("软件工程","软件"));
    7. computerCollege.add(new Department("计算机科学与技术","计算机科学与技术"));
    8. messageCollege.add(new Department("电子信息","电子信息"));
    9. messageCollege.add(new Department("通信工程","通信工程"));
    10. university.add(computerCollege);
    11. university.add(messageCollege);
    12. university.print();
    13. }
    14. }

     结果

    -------------大学------------------------
    -------------计算机学院------------------------
    软件工程   软件
    计算机科学与技术   计算机科学与技术
    -------------信息与工程学院------------------------
    电子信息   电子信息
    通信工程   通信工程

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

    Java 的集合类HashMap就使用了组合模式 

    进入Map接口查看,其中的put方法仅为抽象方法 

    1. public interface Map {
    2. V put(K key, V value);
    3. //......
    4. }

    注意到Map接口的实现类AbstractMap是个抽象类,类似于组合模式的Component(抽象构建)

    其中重写 put 方法时,默认实现,抛出不支持操作的异常对象

    1. public abstract class AbstractMap implements Map {
    2. public V put(K var1, V var2) {
    3. throw new UnsupportedOperationException();
    4. }
    5. // ......
    6. }

    AbstractMap的子类HashMap,类似于组合模式的Composite(中间构建) 

    实现了 put方法,可以看到存入了Node节点中

    1. public class HashMap extends AbstractMap implements Map, Cloneable, Serializable {
    2. public V put(K var1, V var2) {
    3. return this.putVal(hash(var1), var1, var2, false, true);
    4. }
    5. final V putVal(int var1, K var2, V var3, boolean var4, boolean var5) {
    6. HashMap.Node[] var6;
    7. int var8;
    8. if ((var6 = this.table) == null || (var8 = var6.length) == 0) {
    9. var8 = (var6 = this.resize()).length;
    10. }
    11. Object var7;
    12. int var9;
    13. if ((var7 = var6[var9 = var8 - 1 & var1]) == null) {
    14. var6[var9] = this.newNode(var1, var2, var3, (HashMap.Node)null);
    15. } else {
    16. Object var10;
    17. Object var11;
    18. if (((HashMap.Node)var7).hash == var1 && ((var11 = ((HashMap.Node)var7).key) == var2 || var2 != null && var2.equals(var11))) {
    19. var10 = var7;
    20. } else if (var7 instanceof HashMap.TreeNode) {
    21. var10 = ((HashMap.TreeNode)var7).putTreeVal(this, var6, var1, var2, var3);
    22. } else {
    23. int var12 = 0;
    24. while(true) {
    25. if ((var10 = ((HashMap.Node)var7).next) == null) {
    26. ((HashMap.Node)var7).next = this.newNode(var1, var2, var3, (HashMap.Node)null);
    27. if (var12 >= 7) {
    28. this.treeifyBin(var6, var1);
    29. }
    30. break;
    31. }
    32. if (((HashMap.Node)var10).hash == var1 && ((var11 = ((HashMap.Node)var10).key) == var2 || var2 != null && var2.equals(var11))) {
    33. break;
    34. }
    35. var7 = var10;
    36. ++var12;
    37. }
    38. }
    39. //......
    40. }

     Node类似于组合模式的叶子节点 Leaf

    1. static class Node implements Entry {
    2. final int hash;
    3. final K key;
    4. V value;
    5. HashMap.Node next;
    6. Node(int var1, K var2, V var3, HashMap.Node var4) {
    7. this.hash = var1;
    8. this.key = var2;
    9. this.value = var3;
    10. this.next = var4;
    11. }
    12. public final K getKey() {
    13. return this.key;
    14. }
    15. public final V getValue() {
    16. return this.value;
    17. }
    18. public final String toString() {
    19. return this.key + "=" + this.value;
    20. }
    21. public final int hashCode() {
    22. return Objects.hashCode(this.key) ^ Objects.hashCode(this.value);
    23. }
    24. public final V setValue(V var1) {
    25. Object var2 = this.value;
    26. this.value = var1;
    27. return var2;
    28. }
    29. public final boolean equals(Object var1) {
    30. if (var1 == this) {
    31. return true;
    32. } else {
    33. if (var1 instanceof Entry) {
    34. Entry var2 = (Entry)var1;
    35. if (Objects.equals(this.key, var2.getKey()) && Objects.equals(this.value, var2.getValue())) {
    36. return true;
    37. }
    38. }
    39. return false;
    40. }
    41. }
    42. }

    三、组合模式的注意事项和细节

    1)简化客户端操作。客户端只需要面对一致的对象而不用考虑整体部分或者节点叶子的问题

    2)具有较强的扩展性。当我们要更改组合对象时,我们只需要调整内部的层次关系,客户端不用做出任何改动。

    3)方便创建出复杂的层次结构。客户端不用理会组合里面的组成细节,容易添加节点或者叶子从而创建出复杂的树形结构

    4)需要遍历组织机构,或者处理的对象具有树形结构时,非常适合使用组合模式。

    5)要求较高的抽象性,如果节点和叶子有很多差异性的话,比如很多方法和属性都不一样,不适合使用组合模式 

  • 相关阅读:
    spark-submit 高频可选参数及作用
    深度学习实战53-行业描述分类的实战应用:基于ALBERT模型和PyTorch框架的解析
    数据结构小记【Python/C++版】——栈篇
    二叉搜索树的本质
    用frp搞个内网穿透
    [机缘参悟-119] :一个IT人的反思:反者道之动;弱者,道之用 VS 恒者恒强,弱者恒弱的马太效应
    2022CCPC预选赛C Guess(博弈)
    python发送邮件
    RPA技术介绍与应用价值
    ajax笔记二
  • 原文地址:https://blog.csdn.net/qq_51409098/article/details/126903252