组合模式(Composite Pattern),又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。这种类型的设计模式属于结构型模式,它创建了对象组的树形结构。
这种模式创建了一个包含自己对象组的类。该类提供了修改相同对象组的方式。
介绍
意图:将对象组合成树形结构以表示"部分-整体"的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
主要解决:它在我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以向处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦。
何时使用: 1、您想表示对象的部分-整体层次结构(树形结构)。 2、您希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。
如何解决:树枝和叶子实现统一接口,树枝内部组合该接口。
关键代码:树枝内部组合该接口,并且含有内部属性 List,里面放 Component。
应用实例: 1、算术表达式包括操作数、操作符和另一个操作数,其中,另一个操作符也可以是操作树、操作符和另一个操作数。 2、在 JAVA AWT 和 SWING 中,对于 Button 和 Checkbox 是树叶,Container 是树枝。
优点: 1、高层模块调用简单。 2、节点自由增加。
缺点:在使用组合模式时,其叶子和树枝的声明都是实现类,而不是接口,违反了依赖倒置原则。
使用场景:部分、整体场景,如树形菜单,文件、文件夹的管理。
注意事项:定义时为具体类。
下面一个例子是从项目里面剥离出来的,
车载gps服务商可以用到组合模式
* 特点:
* 1.有层级关系
* 2.各级服务商都有相同的操作 为客户(假设是汽车租赁公司)安装车载gps终端,同一个客户,假设名字叫讯芯汽车租赁公司,它可能在宿迁有车子要安装gps,在扬州也有车子要安装gps,那他不管去到哪一级服务商那儿去安装,只要每安装完成一台gps终端,会自动计费到系统,最后再 统一缴费或者从预付费里扣除。
抽象服务商类
1 /** 2 * 抽象服务商类 3 * @author ko 4 * 5 */ 6 public abstract class AbstractFacilitator { 7 8 protected String name; 9 protected String pwd; 10 protected String address; 11 12 protected List<AbstractFacilitator> subordinate;// 下级服务商集合 13 14 public AbstractFacilitator(String name, String pwd, String address) { 15 this.name = name; 16 this.pwd = pwd; 17 this.address = address; 18 subordinate = new ArrayList<>(); 19 } 20 21 /** 22 * 每个服务商都有的业务操作(给客户安装gps终端) 23 * @param cusName 客户名(汽车租赁公司名) 24 * @param gpsNum 要安装的gps台数 25 */ 26 public abstract void installGpsTerminal(String cusName,int gpsNum); 27 28 // 增加 29 public abstract void add(AbstractFacilitator f); 30 31 // 删除 32 public abstract void remove(AbstractFacilitator f); 33 34 // 获取下属服务商集合(只是下一级,不是所有的下级,那样的话需要递归) 35 public abstract List<AbstractFacilitator> getSubordinate(); 36 37 }
车载gps服务商类
1 /** 2 * 车载gps服务商 3 * 特点: 4 * 1.有层级关系 5 * 2.各级服务商都有相同的操作 为客户(假设是汽车租赁公司)安装车载gps终端,同一个客户,假设名字叫讯芯汽车租赁公司,它可能在宿迁有车子 6 * 要安装gps,在扬州也有车子要安装gps,那他不管去到哪一级服务商那儿去安装,只要每安装完成一台gps终端,会自动计费到系统,最后再 7 * 统一缴费或者从预付费里扣除 8 * @author ko 9 * 10 */ 11 public class GpsFacilitator extends AbstractFacilitator { 12 13 14 public GpsFacilitator(String name, String pwd, String address) { 15 super(name, pwd, address); 16 } 17 18 @Override 19 public void installGpsTerminal(String cusName, int gpsNum) { 20 try { 21 Thread.sleep((new Random().nextInt(5)+1)*100*gpsNum);// 模拟安装gps耗时 22 } catch (InterruptedException e) { 23 e.printStackTrace(); 24 } 25 System.out.println("服务商 "+name+"为"+cusName+"安装了"+gpsNum+"台gps终端"); 26 double surplus = TollCharge.preDeposit.get(cusName).subtract(TollCharge.unitPrice.multiply(new BigDecimal(gpsNum))).doubleValue(); 27 System.out.println("本次扣费:"+TollCharge.unitPrice.multiply(new BigDecimal(gpsNum)).doubleValue()+"元,"+cusName+"剩余:"+surplus+"元"); 28 29 // 重置客户预存的钱 30 TollCharge.preDeposit.put("xunxin", new BigDecimal(surplus)); 31 } 32 33 @Override 34 public void add(AbstractFacilitator f) { 35 subordinate.add(f); 36 } 37 38 @Override 39 public void remove(AbstractFacilitator f) { 40 subordinate.remove(f); 41 } 42 43 @Override 44 public List<AbstractFacilitator> getSubordinate() { 45 return subordinate; 46 } 47 48 49 50 }
收费管理类
1 /** 2 * 收费管理 3 * @author ko 4 * 5 */ 6 public class TollCharge { 7 8 public static final BigDecimal unitPrice = new BigDecimal(20); 9 10 public static Map<String, BigDecimal> preDeposit = new HashMap<>();// 客户(汽车租赁公司)预存的钱 11 12 static{ 13 preDeposit.put("xunxin", new BigDecimal(10000));// 讯芯预存的钱 14 // 。。。。 15 } 16 }
测试类
1 public class Test { 2 public static void main(String[] args) { 3 // 江苏总服务商 4 GpsFacilitator jiangsu_gps = new GpsFacilitator("gps jiangsu", "123456", "Nanjing city of Jiangsu Province"); 5 // 宿迁分服务商 6 GpsFacilitator suqian_gps = new GpsFacilitator("gps suqian", "123456", "Suqian city of Jiangsu Province"); 7 // 扬州分服务商 8 GpsFacilitator yangzhou_gps = new GpsFacilitator("gps yangzhou", "123456", "Yangzhou city of Jiangsu Province"); 9 // 宿迁宿城分服务商 10 GpsFacilitator sucheng_gps = new GpsFacilitator("gps sucheng", "123456", "Sucheng District of Jiangsu Province"); 11 // 宿迁宿豫分服务商 12 GpsFacilitator suyu_gps = new GpsFacilitator("gps suyu", "123456", "Suyu District of Jiangsu Province"); 13 // 扬州高邮分服务商 14 GpsFacilitator gaoyou_gps = new GpsFacilitator("gps gaoyou", "123456", "Gaoyou District of Jiangsu Province"); 15 // 扬州邗江分服务商 16 GpsFacilitator hanjiang_gps = new GpsFacilitator("gps hanjiang", "123456", "Hanjiang District of Jiangsu Province"); 17 18 // 添加子服务商 19 jiangsu_gps.add(suqian_gps); 20 jiangsu_gps.add(yangzhou_gps); 21 22 suqian_gps.add(sucheng_gps); 23 suqian_gps.add(suyu_gps); 24 yangzhou_gps.add(gaoyou_gps); 25 yangzhou_gps.add(hanjiang_gps); 26 27 jiangsu_gps.installGpsTerminal("xunxin", 33);// 江苏总服务商给讯芯安装33台gps终端 28 suqian_gps.installGpsTerminal("xunxin", 25);// 宿迁分服务商给讯芯安装25台gps终端 29 hanjiang_gps.installGpsTerminal("xunxin", 15);// 扬州邗江分服务商给讯芯安装15台gps终端 30 31 System.out.println("江苏总服务商有下属服务商:"+jiangsu_gps.getSubordinate().size()+"个"); 32 jiangsu_gps.remove(suqian_gps);// 移除宿迁分服务商 33 System.out.println("江苏总服务商有下属服务商:"+jiangsu_gps.getSubordinate().size()+"个"); 34 } 35 }
打印结果
服务商 gps jiangsu为xunxin安装了33台gps终端 本次扣费:660.0元,xunxin剩余:9340.0元 服务商 gps suqian为xunxin安装了25台gps终端 本次扣费:500.0元,xunxin剩余:8840.0元 服务商 gps hanjiang为xunxin安装了15台gps终端 本次扣费:300.0元,xunxin剩余:8540.0元 江苏总服务商有下属服务商:2个 江苏总服务商有下属服务商:1个