设计模式之组合模式学习理解

组合模式(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个
原文地址:https://www.cnblogs.com/shamo89/p/7155617.html