设计模式之禅16
来源:互联网 发布:数据存储安全 编辑:程序博客网 时间:2024/06/05 04:58
设计模式之禅16
真刀实枪之组合模式
- 从公司的人事架构谈起吧
- 公司的组织架构
- 从上图中可以分析出:
- 有分支的节点(树枝节点)
- 无分支的节点(叶子节点)
- 根节点(无父节点)
- 公司的组织架构
- 有了树状结构图,再看看类图长啥样吧!
这个类图是有缺陷的,等会儿继续修改,现在先看下这个不成熟类图的代码
IRoot
package com.peng.zh;import java.util.ArrayList;/** * @author kungfu~peng * @data 2017年11月24日 * @description */public interface IRoot { // 得到总经理想要的信息 public String getInfo(); // 添加树枝节点 public void add(IBranch banch); // 添加叶子节点 public void add(ILeaf leaf); // 遍历节点 public ArrayList getSubordinateInfo();}
Root
package com.peng.zh;import java.util.ArrayList;/** * @author kungfu~peng * @data 2017年11月24日 * @description */public class Root implements IRoot { // 保存根节点下的树枝节点和叶子节点 private ArrayList subordinateList = new ArrayList(); // 根节点的名称 private String name = ""; // 根节点的职位 private String position = ""; // 根节点的薪水 private int salary = 0; // 通过构造函数传递进来的总经理的信息 Root(String name, String position, int salary) { super(); this.name = name; this.position = position; this.salary = salary; } @Override public String getInfo() { String info = ""; info += "根节点名称:" + this.name + ",根节点职位:" + this.position + ",根节点薪水:" + this.salary; return info; } @Override public void add(IBranch branch) { this.subordinateList.add(branch); } @Override public void add(ILeaf leaf) { this.subordinateList.add(leaf); } @Override public ArrayList getSubordinateInfo() { return this.subordinateList; }}
IBranch
package com.peng.zh;import java.util.ArrayList;/** * @author kungfu~peng * @data 2017年11月24日 * @description */public interface IBranch { // 得到信息 public String getInfo(); // 添加树枝节点 public void add(IBranch banch); // 添加叶子节点 public void add(ILeaf leaf); // 遍历节点 public ArrayList getSubordinateInfo();}
Branch
package com.peng.zh;import java.util.ArrayList;/** * @author kungfu~peng * @data 2017年11月24日 * @description */public class Branch implements IBranch { // 保存树枝节点下的树枝节点和叶子节点 private ArrayList subordinateList = new ArrayList(); // 树枝节点的名称 private String name = ""; // 树枝节点的职位 private String position = ""; // 树枝节点的薪水 private int salary = 0; // 通过构造函数传递进来的树枝节点的信息 Branch(String name, String position, int salary) { super(); this.name = name; this.position = position; this.salary = salary; } @Override public String getInfo() { String info = ""; info += "树枝节点名称:" + this.name + ",树枝节点职位:" + this.position + ",树枝节点薪水:" + this.salary; return info; } @Override public void add(IBranch branch) { this.subordinateList.add(branch); } @Override public void add(ILeaf leaf) { this.subordinateList.add(leaf); } @Override public ArrayList getSubordinateInfo() { return this.subordinateList; }}
ILeaf
package com.peng.zh;import java.util.ArrayList;/** * @author kungfu~peng * @data 2017年11月24日 * @description */public interface ILeaf { // 得到信息 public String getInfo();}
Leaf
package com.peng.zh;import java.util.ArrayList;/** * @author kungfu~peng * @data 2017年11月24日 * @description */public class Leaf implements ILeaf { // 叶子节点的名称 private String name = ""; // 叶子节点的职位 private String position = ""; // 叶子节点的薪水 private int salary = 0; // 通过构造函数传递进来的叶子节点的信息 Leaf(String name, String position, int salary) { super(); this.name = name; this.position = position; this.salary = salary; } @Override public String getInfo() { String info = ""; info += "叶子节点名称:" + this.name + ",叶子节点职位:" + this.position + ",叶子节点薪水:" + this.salary; return info; }}
Client
package com.peng.zh;import java.util.ArrayList;/** * @author kungfu~peng * @data 2017年11月24日 * @description */public class Client { public static void main(String[] args) { // 先产生根节点 IRoot ceo = new Root("王大麻子", "总经理", 100000); // 产生三个部门经理 IBranch developDep = new Branch("刘大瘸子", "研发部门经理", 10000); IBranch salesDep = new Branch("马二拐子", "销售部门经理", 20000); IBranch financeDep = new Branch("赵三驼子", "财务部门经理", 30000); // 两个小组长 IBranch firstDepGroup = new Branch("杨三也斜", "开发一组组长", 5000); IBranch secondDepGrooup = new Branch("吴大棒槌", "开发二组组长", 6000); // 研发部经理 ILeaf zhengLaoLiu = new Leaf("郑老六", "研发部副总", 20000); // 员工 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); // 组装总经理 ceo.add(developDep); ceo.add(salesDep); ceo.add(financeDep); ceo.add(k); // 组装研发部门 developDep.add(firstDepGroup); developDep.add(secondDepGrooup); developDep.add(zhengLaoLiu); // 组装第一个开发小组 firstDepGroup.add(a); firstDepGroup.add(c); firstDepGroup.add(d); // 组装第二个开发小组 secondDepGrooup.add(e); secondDepGrooup.add(f); secondDepGrooup.add(g); // 组装销售部 salesDep.add(h); salesDep.add(i); // 组装财务部 financeDep.add(j); // 打印出来整个树形结构 System.out.println(ceo.getInfo()); getAllSubordinateInfo(ceo.getSubordinateInfo()); } private static void getAllSubordinateInfo(ArrayList subordinateInfo) { int length = subordinateInfo.size(); for (int i = 0; i < length; i++) { Object s = subordinateInfo.get(i); if (s instanceof Leaf) { ILeaf employee = (ILeaf) s; System.out.println(employee.getInfo()); } else { IBranch branch = (IBranch) s; System.out.println(branch.getInfo()); // 递归 getAllSubordinateInfo(branch.getSubordinateInfo()); } } }}
- 执行结果
根节点名称:王大麻子,根节点职位:总经理,根节点薪水:100000树枝节点名称:刘大瘸子,树枝节点职位:研发部门经理,树枝节点薪水:10000树枝节点名称:杨三也斜,树枝节点职位:开发一组组长,树枝节点薪水:5000叶子节点名称:a,叶子节点职位:开发人员,叶子节点薪水:2000叶子节点名称:c,叶子节点职位:开发人员,叶子节点薪水:2000叶子节点名称:d,叶子节点职位:开发人员,叶子节点薪水:2000树枝节点名称:吴大棒槌,树枝节点职位:开发二组组长,树枝节点薪水:6000叶子节点名称:e,叶子节点职位:开发人员,叶子节点薪水:2000叶子节点名称:f,叶子节点职位:开发人员,叶子节点薪水:2000叶子节点名称:g,叶子节点职位:开发人员,叶子节点薪水:2000叶子节点名称:郑老六,叶子节点职位:研发部副总,叶子节点薪水:20000树枝节点名称:马二拐子,树枝节点职位:销售部门经理,树枝节点薪水:20000叶子节点名称:h,叶子节点职位:销售人员,叶子节点薪水:5000叶子节点名称:i,叶子节点职位:销售人员,叶子节点薪水:4000树枝节点名称:赵三驼子,树枝节点职位:财务部门经理,树枝节点薪水:30000叶子节点名称:j,叶子节点职位:财务人员,叶子节点薪水:5000叶子节点名称:k,叶子节点职位:ceo秘书人员,叶子节点薪水:8000
- 好,代码写完,把刚刚遗留的问题来找一下:
- getInfo每个接口都有,为什么不抽象出来?
- Root和Branch类有什么差别?
- 根节点本来就是树枝节点的一种,为什么要定义成两个接口?
- 若果我要增加一个任职期限,是不是所有的都要修改?
- 如果我要后续遍历,能做到吗?
问题很多,一个一个解决
先说抽象问题,确实可以抽象出来,修改下类图
- 修改1
- 仔细看这个图,能不能发现还有问题--想想接口的作用是什么?定义共性,既然是这样,那getInfo方法也可以封装啦,再继续修改
- 修改2
- 类图上增加了一个ICorp接口,它是公司所有员工的接口类
新类图的代码
ICorp
package zh2;/** * @author kungfu~peng * @data 2017年11月24日 * @description */public interface ICorp { // 获取信息 public String getInfo();}
ILeaf
package zh2;/** * @author kungfu~peng * @data 2017年11月24日 * @description */public interface ILeaf extends ICorp {}
Leaf
package zh2;/** * @author kungfu~peng * @data 2017年11月24日 * @description */public class Leaf implements ILeaf { // 叶子节点的名称 private String name = ""; // 叶子节点的职位 private String position = ""; // 叶子节点的薪水 private int salary = 0; // 通过构造函数传递进来的叶子节点的信息 Leaf(String name, String position, int salary) { super(); this.name = name; this.position = position; this.salary = salary; } @Override public String getInfo() { String info = ""; info += "叶子节点名称:" + this.name + ",叶子节点职位:" + this.position + ",叶子节点薪水:" + this.salary; return info; }}
IBranch
package zh2;import java.util.ArrayList;/** * @author kungfu~peng * @data 2017年11月24日 * @description */public interface IBranch extends ICorp { // 增高增加小兵 public void addSubordinate(ICorp corp); // 获得下属信息 public ArrayList<ICorp> getSubordinate(); // 删除下属--没用到,这里省略}
Branch
package zh2;import java.util.ArrayList;/** * @author kungfu~peng * @data 2017年11月24日 * @description */public class Branch implements IBranch { // 保存节点下的树枝节点和叶子节点 private ArrayList<ICorp> subordinateList = new ArrayList<ICorp>(); // 树枝节点的名称 private String name = ""; // 树枝节点的职位 private String position = ""; // 树枝节点的薪水 private int salary = 0; // 通过构造函数传递进来的树枝节点的信息 Branch(String name, String position, int salary) { super(); this.name = name; this.position = position; this.salary = salary; } @Override public String getInfo() { String info = ""; info += "树枝节点名称:" + this.name + ",树枝节点职位:" + this.position + ",树枝节点薪水:" + this.salary; return info; } @Override public void addSubordinate(ICorp corp) { this.subordinateList.add(corp); } @Override public ArrayList<ICorp> getSubordinate() { return this.subordinateList; }}
Client
package zh2;import java.util.ArrayList;/** * @author kungfu~peng * @data 2017年11月24日 * @description */public class Client { public static void main(String[] args) { // 先产生根节点 Branch ceo = new Branch("王大麻子", "总经理", 100000); // 产生三个部门经理 IBranch developDep = new Branch("刘大瘸子", "研发部门经理", 10000); IBranch salesDep = new Branch("马二拐子", "销售部门经理", 20000); IBranch financeDep = new Branch("赵三驼子", "财务部门经理", 30000); // 两个小组长 IBranch firstDepGroup = new Branch("杨三也斜", "开发一组组长", 5000); IBranch secondDepGrooup = new Branch("吴大棒槌", "开发二组组长", 6000); // 研发部经理 ILeaf zhengLaoLiu = new Leaf("郑老六", "研发部副总", 20000); // 员工 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); // 组装总经理 ceo.addSubordinate(developDep); ceo.addSubordinate(salesDep); ceo.addSubordinate(financeDep); ceo.addSubordinate(k); // 组装研发部门 developDep.addSubordinate(firstDepGroup); developDep.addSubordinate(secondDepGrooup); developDep.addSubordinate(zhengLaoLiu); // 组装第一个开发小组 firstDepGroup.addSubordinate(a); firstDepGroup.addSubordinate(c); firstDepGroup.addSubordinate(d); // 组装第二个开发小组 secondDepGrooup.addSubordinate(e); secondDepGrooup.addSubordinate(f); secondDepGrooup.addSubordinate(g); // 组装销售部 salesDep.addSubordinate(h); salesDep.addSubordinate(i); // 组装财务部 financeDep.addSubordinate(j); // 打印出来整个树形结构 System.out.println(ceo.getInfo()); getAllSubordinateInfo(ceo.getSubordinate()); } private static void getAllSubordinateInfo(ArrayList subordinateInfo) { int length = subordinateInfo.size(); for (int i = 0; i < length; i++) { Object s = subordinateInfo.get(i); if (s instanceof Leaf) { ILeaf employee = (ILeaf) s; System.out.println(employee.getInfo()); } else { IBranch branch = (IBranch) s; System.out.println(branch.getInfo()); // 递归 getAllSubordinateInfo(branch.getSubordinate()); } } }}
- 执行结果
树枝节点名称:王大麻子,树枝节点职位:总经理,树枝节点薪水:100000树枝节点名称:刘大瘸子,树枝节点职位:研发部门经理,树枝节点薪水:10000树枝节点名称:杨三也斜,树枝节点职位:开发一组组长,树枝节点薪水:5000叶子节点名称:a,叶子节点职位:开发人员,叶子节点薪水:2000叶子节点名称:c,叶子节点职位:开发人员,叶子节点薪水:2000叶子节点名称:d,叶子节点职位:开发人员,叶子节点薪水:2000树枝节点名称:吴大棒槌,树枝节点职位:开发二组组长,树枝节点薪水:6000叶子节点名称:e,叶子节点职位:开发人员,叶子节点薪水:2000叶子节点名称:f,叶子节点职位:开发人员,叶子节点薪水:2000叶子节点名称:g,叶子节点职位:开发人员,叶子节点薪水:2000叶子节点名称:郑老六,叶子节点职位:研发部副总,叶子节点薪水:20000树枝节点名称:马二拐子,树枝节点职位:销售部门经理,树枝节点薪水:20000叶子节点名称:h,叶子节点职位:销售人员,叶子节点薪水:5000叶子节点名称:i,叶子节点职位:销售人员,叶子节点薪水:4000树枝节点名称:赵三驼子,树枝节点职位:财务部门经理,树枝节点薪水:30000叶子节点名称:j,叶子节点职位:财务人员,叶子节点薪水:5000叶子节点名称:k,叶子节点职位:ceo秘书人员,叶子节点薪水:8000
getInfo方法都有,是不是可以继续优化,把ICorp接口变化成一个抽象类,将getInfo方法在抽象类中实现
- 再次修改类图
代码实现
Corp
package zh3;/** * @author kungfu~peng * @data 2017年11月25日 * @description */public abstract class Corp { // 树枝节点的名称 private String name = ""; // 树枝节点的职位 private String position = ""; // 树枝节点的薪水 private int salary = 0; // 通过构造函数传递进来的树枝节点的信息 Corp(String name, String position, int salary) { this.name = name; this.position = position; this.salary = salary; } public String getInfo() { String info = ""; info += "树枝节点名称:" + this.name + ",树枝节点职位:" + this.position + ",树枝节点薪水:" + this.salary; return info; }}
Branch
package zh3;import java.util.ArrayList;import zh2.ICorp;/** * @author kungfu~peng * @data 2017年11月25日 * @description */public class Branch extends Corp { // 保存节点下的树枝节点和叶子节点 private ArrayList<Corp> subordinateList = new ArrayList<Corp>(); Branch(String name, String position, int salary) { super(name, position, salary); } // 增加下属 public void addSubordinate(Corp corp) { this.subordinateList.add(corp); } // 我有哪些下属 public ArrayList<Corp> getSubordinate() { return this.subordinateList; }}
Leaf
package zh3;/** * @author kungfu~peng * @data 2017年11月25日 * @description */public class Leaf extends Corp { Leaf(String name, String position, int salary) { super(name, position, salary); }}
Client
package zh3;import java.util.ArrayList;/** * @author kungfu~peng * @data 2017年11月25日 * @description */public class Client { public static void main(String[] args) { // 先产生根节点 Branch ceo = new Branch("王大麻子", "总经理", 100000); // 产生三个部门经理 Branch developDep = new Branch("刘大瘸子", "研发部门经理", 10000); Branch salesDep = new Branch("马二拐子", "销售部门经理", 20000); Branch financeDep = new Branch("赵三驼子", "财务部门经理", 30000); // 两个小组长 Branch firstDepGroup = new Branch("杨三也斜", "开发一组组长", 5000); Branch secondDepGrooup = new Branch("吴大棒槌", "开发二组组长", 6000); // 研发部经理 Leaf zhengLaoLiu = new Leaf("郑老六", "研发部副总", 20000); // 员工 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); // 组装总经理 ceo.addSubordinate(developDep); ceo.addSubordinate(salesDep); ceo.addSubordinate(financeDep); ceo.addSubordinate(k); // 组装研发部门 developDep.addSubordinate(firstDepGroup); developDep.addSubordinate(secondDepGrooup); developDep.addSubordinate(zhengLaoLiu); // 组装第一个开发小组 firstDepGroup.addSubordinate(a); firstDepGroup.addSubordinate(c); firstDepGroup.addSubordinate(d); // 组装第二个开发小组 secondDepGrooup.addSubordinate(e); secondDepGrooup.addSubordinate(f); secondDepGrooup.addSubordinate(g); // 组装销售部 salesDep.addSubordinate(h); salesDep.addSubordinate(i); // 组装财务部 financeDep.addSubordinate(j); // 打印出来整个树形结构 System.out.println(ceo.getInfo()); getAllSubordinateInfo(ceo.getSubordinate()); } private static void getAllSubordinateInfo(ArrayList subordinateInfo) { int length = subordinateInfo.size(); for (int i = 0; i < length; i++) { Object s = subordinateInfo.get(i); if (s instanceof Leaf) { Leaf employee = (Leaf) s; System.out.println(employee.getInfo()); } else { Branch branch = (Branch) s; System.out.println(branch.getInfo()); // 递归 getAllSubordinateInfo(branch.getSubordinate()); } } }}
- 执行结果
树枝节点名称:王大麻子,树枝节点职位:总经理,树枝节点薪水:100000树枝节点名称:刘大瘸子,树枝节点职位:研发部门经理,树枝节点薪水:10000树枝节点名称:杨三也斜,树枝节点职位:开发一组组长,树枝节点薪水:5000树枝节点名称:a,树枝节点职位:开发人员,树枝节点薪水:2000树枝节点名称:c,树枝节点职位:开发人员,树枝节点薪水:2000树枝节点名称:d,树枝节点职位:开发人员,树枝节点薪水:2000树枝节点名称:吴大棒槌,树枝节点职位:开发二组组长,树枝节点薪水:6000树枝节点名称:e,树枝节点职位:开发人员,树枝节点薪水:2000树枝节点名称:f,树枝节点职位:开发人员,树枝节点薪水:2000树枝节点名称:g,树枝节点职位:开发人员,树枝节点薪水:2000树枝节点名称:郑老六,树枝节点职位:研发部副总,树枝节点薪水:20000树枝节点名称:马二拐子,树枝节点职位:销售部门经理,树枝节点薪水:20000树枝节点名称:h,树枝节点职位:销售人员,树枝节点薪水:5000树枝节点名称:i,树枝节点职位:销售人员,树枝节点薪水:4000树枝节点名称:赵三驼子,树枝节点职位:财务部门经理,树枝节点薪水:30000树枝节点名称:j,树枝节点职位:财务人员,树枝节点薪水:5000树枝节点名称:k,树枝节点职位:ceo秘书人员,树枝节点薪水:8000
组合模式的定义
- Composite Pattern
- 也叫合成模式或整体-部分模式,主要是描述部分与整体的关系
- Compose objects into tree structures to represent part-whole hirearchies.Composite lets clients treat individual objects and compositions of objects uniformly.(将对象组合成树形结构,以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性)
通用类图
- 几个角色
- Component抽象构建角色:可以定义属性和方法
- Leaf叶子构件:遍历的最小单位
- Composite树枝构件:中间节点或根节点
- 通用代码这里不再赘述
组合模式的应用
- 组合模式的优点
- 高层模块调用简单
- 节点自由增加
- 组合模式的缺点
- 场景类直接使用了树叶节点和树枝节点,这在面向接口编程上是很不恰当的,与依赖原则冲突
- 使用场景
- 维护和展示“部分-整体”关系的场景--树形菜单、文件和文件夹管理
- 从一个整体中能够独立出部分模块或功能的场景
组合模式的注意事项
- 只要是树形结构就考虑组合模式--体现“部分-整体”关系的时候
组合模式的扩展
- 安全模式的组合模式【之前写的就是】
- 透明的组合模式
- 类图
- 透明模式就是将组合使用的方法放到抽象类中,不管是叶子还是树枝都有这个方法,通过判断getChild的返回值确定是叶子节点还是树枝节点,如果处理不当,运行期间会出问题
- 不是很建议这种方式
- 代码--注意叶子节点的add方法的重写--抛出“不支持请求异常”即可--throw new UnsupportedOperationException();
- 类图
- 组合模式的遍历
- 上到下【上面的已经实现】
- 下到上【增加parent】
- 类图
- 代码(看了这么多,自己动手试一试)
最佳实践
- 页面结构【top,center(left,right),bottom】
- JavaScript
- xml
- 血缘关系
声明
- 摘自秦小波《设计模式之禅》第2版;
- 仅供学习,严禁商业用途;
- 代码手写,没有经编译器编译,有个别错误,自行根据上下文改正;
阅读全文
0 0
- 设计模式之禅16
- 设计模式之禅
- 设计模式之禅
- 设计模式之禅
- 设计模式之禅
- 设计模式之禅
- 设计模式之禅
- 设计模式之禅
- 《设计模式之禅》笔记16 -- 组合模式
- [设计模式]<<设计模式之禅>>模板方法模式
- 《设计模式之禅》目录
- 《设计模式之禅》前言
- 《设计模式之禅》书评
- 《设计模式之禅》书评
- 初读《设计模式之禅》
- 《设计模式之禅》书评
- 《设计模式之禅》摘记
- 设计模式之禅读书笔记
- unicode和utf8的区别
- 个人总结45
- 第五届光电信息协会竞赛——XXXX
- php中的布尔值
- 文章标题
- 设计模式之禅16
- day7_类的重要方法和socket基础
- 菱形和水仙花数
- python 3.x 字典的11种方法
- Codeforces --- Mahmoud and Ehab and the MEX
- 深入了解PHP【生命周期】
- Item 11:在赋值操作符中处理自我赋值【effective C++读书笔记】
- VisualSVN Server v3.7
- Android 退出登录功能