首页 >> 大全

设计模式之——组合模式 Composite Pattern

2023-12-21 大全 31 作者:考证青年

引例

在介绍之前我们先来看一个例子,是关于公司的人事管理系统的:

这是一个典型的树形结构,那么我们怎么才能用代码表示他呢?

分析:

总共有两种不同性质的节点

分支的节点:

那这么说,定义三个类不就行了,如下图:

那我们就按照这个类图实现一下代码:

首先是 根节点接口 :

/*** 根节点接口** @author wang suo* @version 1.0* @date 2020/12/21 0021 22:36*/
public interface IRoot {/*** 得到总经理的信息** @return 返回信息*/String getInfo();/*** 总经理下边要有小兵-要能增加小兵-比如研发经理-这是树枝节点** @param iBranch 有分支的节点*/void add(IBranch iBranch);/*** 增加树叶节点的方法** @param iLeaf 叶子节点*/void add(ILeaf iLeaf);/*** 还要能进行遍历-不可能总经理不知道他收下有多少人** @return 返回所有手下的[集合]*/List getSubordinateInfo();
}

根节点接口的 实现类 ,就是我们这里的总经理:

/*** 根节点的实现类** @Author wang suo* @Date 2020/12/22 0022 11:03* @Version 1.0*/
public class Root implements IRoot {/*** 保存根节点下的所有树枝节点和树叶节点*/private List<Object> subordinateList = new ArrayList<>();/*** 根节点的名称*/private String name = "";/*** 根节点的职位*/private String position = "";/*** 根节点的薪水*/private int salary = 0;public Root(String name, String position, int salary) {this.name = name;this.position = position;this.salary = salary;}@Overridepublic String getInfo() {String info = "";info = "名称: " + this.name;info = info + "\t职位: " + this.position;info = info + "\t薪水: " + this.salary;return info;}/*** 增加树叶节点** @param iBranch 有分支的节点*/@Overridepublic void add(IBranch iBranch) {subordinateList.add(iBranch);}/*** 增加叶子节点-直属于总经理的-比如秘书** @param iLeaf 叶子节点*/@Overridepublic void add(ILeaf iLeaf) {subordinateList.add(iLeaf);}@Overridepublic List getSubordinateInfo() {return this.subordinateList;}
}

有分支的节点 接口:

/*** 有分支的节点接口** @author wang suo* @version 1.0* @date 2020/12/21 0021 22:38*/
public interface IBranch {/*** 得到自己的信息** @return 返回信息*/String getInfo();/*** 增加数据节点-例如研发部下面的研发一组** @param iBranch 有分支的节点*/void add(IBranch iBranch);/*** 增加树叶节点的方法** @param iLeaf 叶子节点*/void add(ILeaf iLeaf);/*** 获得下级信息** @return 返回所有手下的[集合]*/List getSubordinateInfo();
}

有分支的节点实现:

/*** 分支的节点实现** @Author wang suo* @Date 2020/12/22 0022 11:16* @Version 1.0*/
public class Branch implements IBranch {/*** 存储子节点的信息*/private List<Object> subordinateList = new ArrayList<>();private String name = "";private String position = "";private int salary = 0;public Branch(String name, String position, int salary) {this.name = name;this.position = position;this.salary = salary;}@Overridepublic String getInfo() {String info = "";info = "名称: " + this.name;info = info + "\t职位: " + this.position;info = info + "\t薪水: " + this.salary;return info;}@Overridepublic void add(IBranch iBranch) {this.subordinateList.add(iBranch);}@Overridepublic void add(ILeaf iLeaf) {this.subordinateList.add(iLeaf);}@Overridepublic List getSubordinateInfo() {return this.subordinateList;}
}

叶子节点 的接口:

/*** 叶子节点的接口** @author wang suo* @version 1.0* @date 2020/12/21 0021 22:38*/
public interface ILeaf {/*** 获取信息** @return 返回信息*/String getInfo();
}

叶子节点的实现:

/*** 叶子节点的实现** @Author wang suo* @Date 2020/12/22 0022 11:20* @Version 1.0*/
public class Leaf implements ILeaf {/*** 叶子叫什么名字*/private String name = "";/*** 叶子的职位*/private String position = "";/*** 叶子的薪水*/private int salary = 0;public Leaf(String name, String position, int salary) {this.name = name;this.position = position;this.salary = salary;}@Overridepublic String getInfo() {String info = "";info = "名称: " + this.name;info = info + "\t职位: " + this.position;info = info + "\t薪水: " + this.salary;return info;}
}

所有的根节点,树枝节点和叶子节点都已经实现了,随后我们实现一下 环境类 :

/*** 场景类** @Author wang suo* @Date 2020/12/22 0022 11:22* @Version 1.0*/
public class Client {public static void main(String[] args) {// 首先产生一个根节点IRoot ceo = new Root("王大麻子", "总经理", 100000);// 产生 3 个部门经理Branch developDep = new Branch("刘大瘸子", "研发部门经理", 10000);Branch salesDep = new Branch("马二拐子", "销售部门经理", 20000);Branch financeDep = new Branch("赵三驼子", "财务部门经理", 30000);// 开发部门的3个小组长IBranch firstDevGroup = new Branch("杨三乜斜", "开发一组组长", 5000);IBranch secondDevGroup = new Branch("吴大棒槌", "开发二组组长", 6000);// 剩下的就是我们这些小兵了,就是路人甲,路人乙ILeaf a = new Leaf("a", "开发人员", 2000);ILeaf b = new Leaf("b", "开发人员", 2000);ILeaf c = new Leaf("c", "开发人员", 2000);ILeaf d = new Leaf("d", "开发人员", 2000);ILeaf e = new Leaf("e", "开发人员", 2000);ILeaf f = new Leaf("f", "开发人员", 2000);ILeaf g = new Leaf("g", "开发人员", 2000);ILeaf h = new Leaf("h", "销售人员", 5000);ILeaf i = new Leaf("i", "销售人员", 4000);ILeaf j = new Leaf("j", "财务人员", 5000);ILeaf k = new Leaf("k", "CEO秘书", 8000);ILeaf zhengLaoLiu = new Leaf("郑老六", "研发部副总", 20000);// 该产生的人都产生出来了,然后我们怎么组装这棵树// 首先是定义总经理下有三个部门经理ceo.add(developDep);ceo.add(salesDep);ceo.add(financeDep);// 总经理下还有一个秘书ceo.add(k);// 定义研发部门下的结构developDep.add(firstDevGroup);developDep.add(secondDevGroup);// 研发部经理下还有一个副总developDep.add(zhengLaoLiu);// 看看开发两个开发小组下有什么firstDevGroup.add(a);firstDevGroup.add(b);firstDevGroup.add(c);secondDevGroup.add(d);secondDevGroup.add(e);secondDevGroup.add(f);// 再看销售部下的人员情况salesDep.add(h);salesDep.add(i);//最后一个财务financeDep.add(j);//树状结构写完毕,然后我们打印出来System.out.println(ceo.getInfo());//打印出来整个树形getAllSubordinateInfo(ceo.getSubordinateInfo());}/*** 遍历并打印整个树** @param subordinateList 树或子树*/private static void getAllSubordinateInfo(List subordinateList) {for (Object o : subordinateList) {if (o instanceof Leaf) {System.out.println(((Leaf) o).getInfo());} else {IBranch branch = (IBranch) o;System.out.println(branch.getInfo());// 递归调用getAllSubordinateInfo(branch.getSubordinateInfo());}}}
}

执行结果:

名称: 王大麻子	职位: 总经理			薪水: 100000
名称: k			职位: CEO秘书		薪水: 8000
名称: 刘大瘸子	职位: 研发部门经理		薪水: 10000
名称: 郑老六		职位: 研发部副经理		薪水: 20000
名称: 杨三乜斜	职位: 开发一组组长		薪水: 5000
名称: a			职位: 开发人员		薪水: 2000
名称: b			职位: 开发人员		薪水: 2000
名称: c			职位: 开发人员		薪水: 2000
名称: 吴大棒槌	职位: 开发二组组长		薪水: 6000
名称: d			职位: 开发人员		薪水: 2000
名称: e			职位: 开发人员		薪水: 2000
名称: f			职位: 开发人员		薪水: 2000
名称: 马二拐子	职位: 销售部门经理		薪水: 20000
名称: h			职位: 销售人员		薪水: 5000
名称: i			职位: 销售人员		薪水: 4000
名称: 赵三驼子	职位: 财务部经理		薪水: 30000
名称: j			职位: 财务人员		薪水: 5000

存在的问题

现在我们来分析一下上面的代码和架构出现的问题:

修改之后的类图

精简之后的代码显得格外简洁,而且环境类只需要直接和抽象类 Corp 关联就可以了,代码如下:

抽象 公司职员类 :

/*** 抽象公司职员类** @Author wang suo* @Date 2020/12/22 0022 19:11* @Version 1.0*/
public abstract class AbstractCorp {/*** 公司每个人都有名称*/private String name = "";/*** 公司每个人都有职位*/private String position = "";/*** 公司每个人都有薪水*/private int salary = 0;/*** 构造方法** @param name     名称* @param position 职位* @param salary   薪水*/public AbstractCorp(String name, String position, int salary) {this.name = name;this.position = position;this.salary = salary;}/*** 获取员工信息** @return 信息*/public String getInfo() {String info = "";info = "名称: " + this.name;info = info + "\t职位: " + this.position;info = info + "\t薪水: " + this.salary;return info;}
}

树枝节点:

/*** 树枝节点** @Author wang suo* @Date 2020/12/22 0022 20:19* @Version 1.0*/
public class Branch extends AbstractCorp {/*** 领导下边有哪些下级领导和小兵*/private List<AbstractCorp> subordinateList = new ArrayList<>();/*** 构造方法** @param name     名称* @param position 职位* @param salary   薪水*/public Branch(String name, String position, int salary) {super(name, position, salary);}/*** 增加一个下属** @param corp 树枝*/public void addSubordinate(AbstractCorp corp) {subordinateList.add(corp);}/*** 我有哪些下属** @return 返回下属*/public List<AbstractCorp> getSubordinate() {return subordinateList;}
}

树叶节点:

/*** 叶子** @Author wang suo* @Date 2020/12/22 0022 20:29* @Version 1.0*/
public class Leaf extends AbstractCorp {/*** 构造方法** @param name     名称* @param position 职位* @param salary   薪水*/public Leaf(String name, String position, int salary) {super(name, position, salary);}
}

修改之后的场景类:

/*** 修改之后的场景类** @Author wang suo* @Date 2020/12/22 0022 20:26* @Version 1.0*/
public class Client {public static void main(String[] args) {//首先是组装一个组织结构出来Branch ceo = compositeCorpTree();//首先把CEO的信息打印出来:System.out.println(ceo.getInfo());//然后是所有员工信息System.out.println(getTreeInfo(ceo));}//把整个树组装出来public static Branch compositeCorpTree() {//首先产生总经理CEOBranch root = new Branch("王大麻子", "总经理", 100000);//把三个部门经理产生出来Branch developDep = new Branch("刘大瘸子", "研发部门经理", 10000);Branch salesDep = new Branch("马二拐子", "销售部门经理", 20000);Branch financeDep = new Branch("赵三驼子", "财务部经理", 30000);//再把三个小组长产生出来Branch firstDevGroup = new Branch("杨三乜斜", "开发一组组长", 5000);Branch secondDevGroup = new Branch("吴大棒槌", "开发二组组长", 6000);//把所有的小兵都产生出来Leaf a = new Leaf("a", "开发人员", 2000);Leaf b = new Leaf("b", "开发人员", 2000);Leaf c = new Leaf("c", "开发人员", 2000);Leaf d = new Leaf("d", "开发人员", 2000);Leaf e = new Leaf("e", "开发人员", 2000);Leaf f = new Leaf("f", "开发人员", 2000);Leaf g = new Leaf("g", "开发人员", 2000);Leaf h = new Leaf("h", "销售人员", 5000);Leaf i = new Leaf("i", "销售人员", 4000);Leaf j = new Leaf("j", "财务人员", 5000);Leaf k = new Leaf("k", "CEO秘书", 8000);Leaf zhengLaoLiu = new Leaf("郑老六", "研发部副经理", 20000);//开始组装//CEO下有三个部门经理和一个秘书root.addSubordinate(k);root.addSubordinate(developDep);root.addSubordinate(salesDep);root.addSubordinate(financeDep);//研发部经理developDep.addSubordinate(zhengLaoLiu);developDep.addSubordinate(firstDevGroup);developDep.addSubordinate(secondDevGroup);//看看开发两个开发小组下有什么firstDevGroup.addSubordinate(a);firstDevGroup.addSubordinate(b);firstDevGroup.addSubordinate(c);secondDevGroup.addSubordinate(d);secondDevGroup.addSubordinate(e);secondDevGroup.addSubordinate(f);//再看销售部下的人员情况salesDep.addSubordinate(h);salesDep.addSubordinate(i);//最后一个财务financeDep.addSubordinate(j);return root;}public static String getTreeInfo(Branch root) {List<AbstractCorp> subordinateList = root.getSubordinate();String info = "";for (AbstractCorp corp : subordinateList) {if (corp instanceof Leaf) {info = info + corp.getInfo() + "\n";} else {// 是个小头目info = info + corp.getInfo() + "\n" + getTreeInfo((Branch) corp);}}return info;}
}

这就是 组合模式 。

组合模式

组合模式依据什么结构__组合模式的分类

组合模式也叫合成模式,有事又叫做部分-整体模式,主要是用来描述整体和部分之间的关系。

组合模式的通用类图:

抽象组件:

public abstract class Component {//个体和整体都具有的共享public void doSomething(){//编写业务逻辑}
}

树枝构件:

public class Composite extends Component {//构件容器private ArrayList<Component> componentArrayList = new ArrayList<Component>();//增加一个叶子构件或树枝构件public void add(Component component){this.componentArrayList.add(component);}//删除一个叶子构件或树枝构件public void remove(Component component){this.componentArrayList.remove(component);}//获得分支下的所有叶子构件和树枝构件public ArrayList<Component> getChildren(){return this.componentArrayList;}
}

树叶构件:

public class Leaf extends Component {/** 可以覆写父类方法* public void doSomething(){* * }*/
}

环境类:

public class Client {public static void main(String[] args) {//创建一个根节点Composite root = new Composite();root.doSomething();//创建一个树枝构件Composite branch = new Composite();//创建一个叶子节点Leaf leaf = new Leaf();//建立整体root.add(branch);branch.add(leaf);		}//通过递归遍历树public static void display(Composite root){for(Component c:root.getChildren()){if(c instanceof Leaf){ //叶子节点c.doSomething();}else{ //树枝节点display((Composite)c);}}}
}

我们发现在环境类中直接使用

Composite root = new Composite();

这个了,违反了依赖倒置原则。

我们再来分析一下组合模式的优点和缺点:

缺点:

组合模式的两种实现

其实组合模式是有两种实现的,分别是 透明模式 和 安全模式 ,我们上面用到的是安全模式,那么透明模式是怎么样的?

类图如下:

我们与安全模式对比一下就非常清楚了,透明模式是把所有的方法都放在抽象类中,这样的话对于树叶节点来说是不安全的,因为在运行期间会遇到问题。

关于我们

最火推荐

小编推荐

联系我们


版权声明:本站内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 88@qq.com 举报,一经查实,本站将立刻删除。备案号:桂ICP备2021009421号
Powered By Z-BlogPHP.
复制成功
微信号:
我知道了