23种设计模式之_组合模式
来源:互联网 发布:jdbc mysql 编辑:程序博客网 时间:2024/06/14 15:47
前言
23种设计模式组合模式也属于一种比较常用的模式,类似层级菜单,公司组织架构,数据结构中的树形结构(root,Branch,Leaf)等等。
Uml通用类图
源码分析
大家在上学的时候应该都学过“数据结构”这门课程吧,还记得其中有一节叫“二叉树”吧,我们上
学那会儿这一章节是必考内容,左子树,右子树,什么先序遍历后序遍历什么,重点就是二叉树的的遍历,
我还记得当时老师就说,考试的时候一定有二叉树的构建和遍历,现在想起来还是觉的老师是正确的,树
状结果在实际项目应用的非常广泛。
咱就先说个最常见的例子,公司的人事管理就是一个典型的树状结构,你想想你公司的结构是不是这样。
最 高 的老大,往下一层一层的管理,最后到我们这层小兵,很典型的树状结构(说明一下,这不是二叉树,有关二叉树的定义可以翻翻以前的教科书),我们今天的任务就是要把这个树状结构实现出来,并且还要把它遍
历一遍,你要确认你建立的树是否有问题呀。
从这个树状结构上分析,有两种节点:有分支的节点(如研发部经理)和无分支的节点(如员工 A、员
工 D 等),我们增加一点学术术语上去,总经理叫做根节点(是不是想到 XML 中的那个根节点 root,那就对
了),类似研发部经理有分支的节点叫做树枝节点,类似员工 A 的无分支的节点叫做树叶节点,都很形象,三个类型的的节点,那是不是定义三个类就可以?好,我们按照这个思路走下去,先看我们自己设计的类
图:
这个类图是初学者最容易想到的类图(如果你已经看明白这个类图的缺陷了,就可以不看下边的实现
了,我是循序渐进的讲课,呵呵),我那来看这个实现:
先看最高级别的根节点的实现
package interfac;import java.util.ArrayList;public interface IRoot { // 得到总经理的信息 public String getInfo(); // 总经理下边要有小兵,那要能增加小兵,比如研发部总经理,这是个树枝节点 public void add(IBranch branch); // 那要能增加树叶节点 public void add(Ileaf leaf); // 既然能增加,那要还要能够遍历,不可能总经理不知道他手下有哪些人 public ArrayList getSubordinateInfo();}
这个根节点就是我们的总经理 CEO,然后看实现类:
package compositemodel;import java.util.ArrayList;import interfac.IBranch;import interfac.IRoot;import interfac.Ileaf;public class RootNode implements IRoot { String name;// 姓名 String postion;// 职位 int pay;// 薪资 ArrayList branchs = new ArrayList(); public RootNode(String name, String postion, int pay) { super(); this.name = name; this.postion = postion; this.pay = pay; } public void add(IBranch branch) { branchs.add(branch); } public void add(Ileaf leaf) { branchs.add(leaf); } public ArrayList getSubordinateInfo() { return this.branchs; } public String getInfo() { return " 姓名:"+this.name+" 职位:"+ this.postion+" 薪资:"+ this.pay ; }}
很简单,通过构造函数传入参数,然后获得信息,还可以增加子树枝节点(部门经理)和叶子节点(秘
书)。我们再来看 IBranch.java:
package interfac;import java.util.ArrayList;public interface IBranch { public String getInfo(); // 总经理下边要有小兵,那要能增加小兵,比如研发部总经理,这是个树枝节点 public void add(IBranch branch); // 那要能增加树叶节点 public void add(Ileaf leaf); // 既然能增加,那要还要能够遍历,不可能总经理不知道他手下有哪些人 public ArrayList getSubordinateInfo();}
下面看树枝节点的实现:
package compositemodel;import java.util.ArrayList;import interfac.IBranch;import interfac.Ileaf;public class BranchNode implements IBranch { String name;// 姓名 String postion;// 职位 int pay;// 薪资 ArrayList branchs = new ArrayList(); public BranchNode(String name, String postion, int pay) { super(); this.name = name; this.postion = postion; this.pay = pay; } public void addSubBranch(IBranch branch) { branchs.add(branch); } public ArrayList getSubordinateInfo() { return this.branchs; } public String getInfo() { return " 姓名:" + this.name + " 职位:" + this.postion + " 薪资:" + this.pay; } public void add(IBranch branch) { branchs.add(branch); } public void add(Ileaf leaf) { branchs.add(leaf); }}
最后看叶子节点,也就是员工的接口:
package interfac;public interface Ileaf { // 得到自己信息 String getInfo();}
以及叶子节点的实现
package compositemodel;import interfac.Ileaf;public class LeafNode implements Ileaf { String name;// 姓名 String postion;// 职位 int pay;// 薪资 public LeafNode(String name, String postion, int pay) { super(); this.name = name; this.postion = postion; this.pay = pay; } public String getInfo() { return " 姓名:" + this.name + " 职位:" + this.postion + " 薪资:" + this.pay; }}
好了,所有的根节点,树枝节点和叶子节点都已经实现了,从总经理、部门经理到最终的员工都已经
实现了,然后的工作就是组装成一个树状结构和遍历这个树状结构,看 Client.java 程序:
package compositemodel;import java.util.ArrayList;import interfac.IBranch;import interfac.IRoot;import interfac.Ileaf;/** * 组合模式适用属性结构 层级关系 * * @author weichyang * */public class Client { public static void main(String[] args) { // 首先产生了一个根节点 IRoot ceo = new RootNode("王大麻子", "总经理", 100000); // 产生三个部门经理,也就是树枝节点 IBranch developDep = new BranchNode("刘大瘸子", "研发部门经理", 10000); IBranch salesDep = new BranchNode("马二拐子", "销售部门经理", 20000); IBranch financeDep = new BranchNode("赵三驼子", "财务部经理", 30000); // 再把三个小组长产生出来 IBranch firstDevGroup = new BranchNode("杨三乜斜", "开发一组组长", 5000); IBranch secondDevGroup = new BranchNode("吴大棒槌", "开发二组组长", 6000); // 剩下的及时我们这些小兵了,就是路人甲,路人乙 Ileaf a = new LeafNode("a", "开发人员", 2000); Ileaf b = new LeafNode("b", "开发人员", 2000); Ileaf c = new LeafNode("c", "开发人员", 2000); Ileaf d = new LeafNode("d", "开发人员", 2000); Ileaf e = new LeafNode("e", "开发人员", 2000); Ileaf f = new LeafNode("f", "开发人员", 2000); Ileaf g = new LeafNode("g", "开发人员", 2000); Ileaf h = new LeafNode("h", "销售人员", 5000); Ileaf i = new LeafNode("i", "销售人员", 4000); Ileaf j = new LeafNode("j", "财务人员", 5000); Ileaf k = new LeafNode("k", "CEO秘书", 8000); Ileaf zhengLaoLiu = new LeafNode("郑老六", "研发部副总", 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()); } // 遍历所有的树枝节点,打印出信息 private static void getAllSubordinateInfo(ArrayList subordinateList) { int length = subordinateList.size(); for (int m = 0; m < length; m++) { // 定义一个ArrayList长度,不要在for循环中每次计算 Object s = subordinateList.get(m); if (s instanceof LeafNode) { // 是个叶子节点,也就是员工 Ileaf employee = (Ileaf) s; System.out.println(((Ileaf) s).getInfo()); } else { IBranch branch = (IBranch) s; System.out.println(branch.getInfo()); // 再递归调用 getAllSubordinateInfo(branch.getSubordinateInfo()); } } }}
运行结果:
姓名:王大麻子 职位:总经理 薪资:100000
姓名:刘大瘸子 职位:研发部门经理 薪资:10000
姓名:杨三乜斜 职位:开发一组组长 薪资:5000
姓名:a 职位:开发人员 薪资:2000
姓名:b 职位:开发人员 薪资:2000
姓名:c 职位:开发人员 薪资:2000
姓名:吴大棒槌 职位:开发二组组长 薪资:6000
姓名:d 职位:开发人员 薪资:2000
姓名:e 职位:开发人员 薪资:2000
姓名:f 职位:开发人员 薪资:2000
姓名:郑老六 职位:研发部副总 薪资:20000
姓名:马二拐子 职位:销售部门经理 薪资:20000
姓名:h 职位:销售人员 薪资:5000
姓名:i 职位:销售人员 薪资:4000
姓名:赵三驼子 职位:财务部经理 薪资:30000
姓名:j 职位:财务人员 薪资:5000
姓名:k 职位:CEO秘书 薪资:8000
和我们期望要的结果一样,一棵完整的树就生成了,而且我们还能够遍历。看类图或程序的时候,你
有没有发觉有问题?getInfo 每个接口都有为什么不能抽象出来?Root 类和 Branch 类有什么差别?为什么
要定义成两个接口两个类?如果我要加一个任职期限,你是不是每个类都需要修改?如果我要后序遍历(从
员工找到他的上级领导)能做吗?——彻底晕菜了!
问题很多,我们一个一个解决,先说抽象的问题,确实可以吧 IBranch 和 IRoot 合并成一个接口,这
个我们先肯定下来,这是个比较大的改动,我们先画个类图:
这个类图还是有点问题的,接口的作用是什么?定义共性,那 ILeaf 和 IBranch 是不是也有共性呢?
有 getInfo(),我们是不是要把这个共性也已经封装起来呢?好,我们再修改一下类图:
类图上有两个接口,ICorp 是公司所有人员的信息的接口类,不管你是经理还是员工,你都有名字,职
位,薪水,这个定义成一个接口没有错,IBranch 有没有必要呢?
先看到Icrop接口
package interfac;public interface ICrop { String getInfo();}实现import interfac.ICrop;import interfac.Ileaf;public class LeafNode implements ICrop { String name;// 姓名 String postion;// 职位 int pay;// 薪资 public LeafNode(String name, String postion, int pay) { super(); this.name = name; this.postion = postion; this.pay = pay; } public String getInfo() { return " 姓名:" + this.name + " 职位:" + this.postion + " 薪资:" + this.pay; }}
小兵就只有这些信息了,我们是具体干活的,我们是管理不了其他同事的,我们来看看那些经理和小
组长是怎么实现的,先看接口:
package interfac;import java.util.ArrayList;public interface IBranch { // 那要能增加树叶节点 public void add(ICrop leaf); // 既然能增加,那要还要能够遍历,不可能总经理不知道他手下有哪些人 public ArrayList getSubordinateInfo();}
实现类
package compositemodel;import java.util.ArrayList;import interfac.IBranch;import interfac.ICrop;import interfac.Ileaf;public class BranchNode implements IBranch, ICrop { String name;// 姓名 String postion;// 职位 int pay;// 薪资 ArrayList branchs = new ArrayList(); public BranchNode(String name, String postion, int pay) { super(); this.name = name; this.postion = postion; this.pay = pay; } public ArrayList getSubordinateInfo() { return this.branchs; } public String getInfo() { return " 姓名:" + this.name + " 职位:" + this.postion + " 薪资:" + this.pay; } public void add(ICrop leaf) { branchs.add(leaf); }}
接口也是很简单的,下面是实现类:
package compositemodel;import java.util.ArrayList;/** * 组合模式适用属性结构 层级关系 * * @author weichyang * */public class Client { public static void main(String[] args) { // 首先产生了一个根节点 BranchNode ceo = new BranchNode("王大麻子", "总经理", 100000); // 产生三个部门经理,也就是树枝节点 BranchNode developDep = new BranchNode("刘大瘸子", "研发部门经理", 10000); BranchNode salesDep = new BranchNode("马二拐子", "销售部门经理", 20000); BranchNode financeDep = new BranchNode("赵三驼子", "财务部经理", 30000); // 再把三个小组长产生出来 BranchNode firstDevGroup = new BranchNode("杨三乜斜", "开发一组组长", 5000); BranchNode secondDevGroup = new BranchNode("吴大棒槌", "开发二组组长", 6000); // 剩下的及时我们这些小兵了,就是路人甲,路人乙 LeafNode a = new LeafNode("a", "开发人员", 2000); LeafNode b = new LeafNode("b", "开发人员", 2000); LeafNode c = new LeafNode("c", "开发人员", 2000); LeafNode d = new LeafNode("d", "开发人员", 2000); LeafNode e = new LeafNode("e", "开发人员", 2000); LeafNode f = new LeafNode("f", "开发人员", 2000); LeafNode g = new LeafNode("g", "开发人员", 2000); LeafNode h = new LeafNode("h", "销售人员", 5000); LeafNode i = new LeafNode("i", "销售人员", 4000); LeafNode j = new LeafNode("j", "财务人员", 5000); LeafNode k = new LeafNode("k", "CEO秘书", 8000); LeafNode zhengLaoLiu = new LeafNode("郑老六", "研发部副总", 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()); } // 遍历所有的树枝节点,打印出信息 private static void getAllSubordinateInfo(ArrayList subordinateList) { int length = subordinateList.size(); for (int m = 0; m < length; m++) { // 定义一个ArrayList长度,不要在for循环中每次计算 Object s = subordinateList.get(m); if (s instanceof LeafNode) { // 是个叶子节点,也就是员工 LeafNode employee = (LeafNode) s; System.out.println(employee.getInfo()); } else { BranchNode branch = (BranchNode) s; System.out.println(branch.getInfo()); // 再递归调用 getAllSubordinateInfo(branch.getSubordinateInfo()); } } }}
运行结果是相同的
一个非常清理的树状人员资源管理图出现了,那我们的程序是否还可以优化?可以!你看 Leaf 和 Branch
中都有 getInfo 信息,是否可以抽象,好,我们抽象一下:
你一看这个图,乐了,能不乐嘛,减少很多工作量了,接口没有了,改成抽象类了,IBranch 接口也没
有了,直接把方法放到了实现类中了,那我们先来看抽象类:
package compositemodel;public abstract class Crop { String name;// 姓名 String postion;// 职位 int pay;// 薪资 public Crop(String name, String postion, int pay) { this.name = name; this.postion = postion; this.pay = pay; } public String getInfo() { return " 姓名:" + this.name + " 职位:" + this.postion + " 薪资:" + this.pay; }}
个改动比较多,就几行代码就完成了,确实就应该这样,下面是小头目的实现类:
package compositemodel;import java.util.ArrayList;public class BranchNode extends Crop { String name;// 姓名 String postion;// 职位 int pay;// 薪资 ArrayList branchs = new ArrayList(); public BranchNode(String name, String postion, int pay) { super(name, postion, pay); } public ArrayList getSubordinateInfo() { return this.branchs; } public void add(Crop leaf) { branchs.add(leaf); }}
两种遍历方式
// 遍历所有的树枝节点,打印出信息
private static void getAllSubordinateInfo(ArrayList subordinateList) { int length = subordinateList.size(); for (int m = 0; m < length; m++) { // 定义一个ArrayList长度,不要在for循环中每次计算 Object s = subordinateList.get(m); if (s instanceof LeafNode) { // 是个叶子节点,也就是员工 LeafNode employee = (LeafNode) s; System.out.println(employee.getInfo()); } else { BranchNode branch = (BranchNode) s; System.out.println(branch.getInfo()); // 再递归调用 getAllSubordinateInfo(branch.getSubordinateInfo()); } } } public static String getTreeInfo(BranchNode root) { ArrayList<Crop> subordinateList = root.getSubordinateInfo(); String info = ""; for (Crop s : subordinateList) { if (s instanceof LeafNode) { // 是员工就直接获得信息 info = info + s.getInfo() + "\n"; } else { // 是个小头目 info = info + s.getInfo() + "\n" + getTreeInfo((BranchNode) s); } } return info; }
就是把用到 ICorp 接口的地方修改为 Corp 抽象类就成了,就上面黄色的部分作了点修改,其他保持不
变,运行结果还是保持一样:
结果一样。
确实是类、接口减少了很多,而且程序也简单很多,但是大家可能还是很迷茫,这个 Client 程序并没
有改变多少呀,非常正确,树的组装你是跑不了的,你要知道在项目中使用数据库来存储这些信息的,你
从数据库中提出出来哪些人要分配到树枝,哪些人要分配到树叶,树枝与树枝、树叶的关系,这些都需要
人去定义
下篇链接:http://blog.csdn.net/o279642707/article/details/64127770
- 23种设计模式之_组合模式
- 设计模式之_组合模式(下)
- 23种设计模式之组合模式
- 23种设计模式之组合模式
- 设计模式_组合模式
- 设计模式_组合模式
- 23设计模式之组合模式(Composite)
- 23设计模式之组合模式(Composite)
- 23中设计模式之组合模式
- 23种设计模式(9)_结构型_组合模式(Composite Pattern)
- 23种设计模式之组合模式(Composite)
- c++ 23种设计模式之组合模式
- 23种设计模式C++实例之组合模式
- 23种设计模式之组合模式(composite)
- 【23种设计模式】之 组合模式(Composite Pattern)
- 设计模式之组合模式
- 设计模式之组合模式
- 设计模式之组合模式
- 461. Hamming Distance
- 判断两个日期大小的方法
- 从USB驱动器运行Windows 10
- MVP的一点理解
- 单词逆序-数据结构和算法
- 23种设计模式之_组合模式
- C ++ primer 笔记
- java生成随机字符
- iOS App图标和启动画面尺寸
- TCP/IP和UDP
- 1070. 结绳(25)
- J2EE项目代码编写规范分享
- 2017-3-16信息技术笔记
- [bigdata054] python3 urllib的timeout测试