GOF23设计模式之桥接模式(bridge)

一、桥接模式概述

  桥接模式核心要点:

    处理多层继承结构,处理多维度变化的场景,将各个维度设计成独立的继承结构,使各个维度可以独立的扩展在抽象层建立关联。

二、桥接模式场景提出与存在问题

  商城系统中常见的商品分类,以电脑为类,如何良好的处理商品分类销售的问题?

  这个场景中有两个变化的维度:品牌、电脑类型。

    

  (1)不使用桥接模式时:

  1 /**
  2  * 不适用桥接模式时的电脑产品按照类型和品牌分类
  3  * @author CL
  4  *
  5  */
  6 public interface Computer {
  7     void sale();
  8 }
  9 
 10 /**
 11  * 类型:台式机
 12  * @author CL
 13  *
 14  */
 15 class Desktop implements Computer {
 16 
 17     @Override
 18     public void sale() {
 19         System.out.println("销售台式机");
 20     }
 21     
 22 }
 23 
 24 /**
 25  * 类型:笔记本
 26  * @author CL
 27  *
 28  */
 29 class Laptop implements Computer {
 30 
 31     @Override
 32     public void sale() {
 33         System.out.println("销售笔记本");
 34     }
 35     
 36 }
 37 
 38 /**
 39  * 类型:平板
 40  * @author CL
 41  *
 42  */
 43 class Pad implements Computer {
 44 
 45     @Override
 46     public void sale() {
 47         System.out.println("销售平板电脑");
 48     }
 49     
 50 }
 51 
 52 /**
 53  * 品牌:联想台式机
 54  * @author CL
 55  *
 56  */
 57 class LenovoDesktop extends Desktop {
 58     @Override
 59     public void sale() {
 60         System.out.println("销售联想台式机");
 61     }
 62 }
 63 
 64 /**
 65  * 品牌:联想笔记本
 66  * @author CL
 67  *
 68  */
 69 class LenovoLaptop extends Desktop {
 70     @Override
 71     public void sale() {
 72         System.out.println("销售联想笔记本");
 73     }
 74 }
 75 
 76 /**
 77  * 品牌:联想平板电脑
 78  * @author CL
 79  *
 80  */
 81 class LenovoPad extends Desktop {
 82     @Override
 83     public void sale() {
 84         System.out.println("销售联想平板电脑");
 85     }
 86 }
 87 
 88 /**
 89  * 品牌:戴尔台式机
 90  * @author CL
 91  *
 92  */
 93 class DellDesktop extends Desktop {
 94     @Override
 95     public void sale() {
 96         System.out.println("销售戴尔台式机");
 97     }
 98 }
 99 
100 /**
101  * 品牌:戴尔笔记本
102  * @author CL
103  *
104  */
105 class DellLaptop extends Desktop {
106     @Override
107     public void sale() {
108         System.out.println("销售戴尔笔记本");
109     }
110 }
111 
112 /**
113  * 品牌:戴尔平板电脑
114  * @author CL
115  *
116  */
117 class DellPad extends Desktop {
118     @Override
119     public void sale() {
120         System.out.println("销售戴尔平板电脑");
121     }
122 }
123 
124 /**
125  * 品牌:华硕台式机
126  * @author CL
127  *
128  */
129 class ASUSDesktop extends Desktop {
130     @Override
131     public void sale() {
132         System.out.println("销售华硕台式机");
133     }
134 }
135 
136 /**
137  * 品牌:华硕笔记本
138  * @author CL
139  *
140  */
141 class ASUSLaptop extends Desktop {
142     @Override
143     public void sale() {
144         System.out.println("销售华硕笔记本");
145     }
146 }
147 
148 /**
149  * 品牌:华硕平板电脑
150  * @author CL
151  *
152  */
153 class ASUSPad extends Desktop {
154     @Override
155     public void sale() {
156         System.out.println("销售华硕平板电脑");
157     }
158 }

  测试:

 1 /**
 2  * 客户端
 3  * @author CL
 4  *
 5  */
 6 public class Client {
 7     
 8     public static void main(String[] args) {
 9         Computer c1 = new LenovoDesktop();
10         c1.sale();
11     }
12 
13 }

  控制台输出:

销售联想台式机

  (2)存在问题

    ① 扩展性问题(类的个数膨胀问题)

     如果要增加一个新的电脑类型,如智能手机,则要增加各个品牌下面的类;

     如果要增加一个新的品牌,也要增加各种电脑类型的类。

    ② 违反了单一职责原则

     一个类有两个职责:品牌+电脑类型。每个类都有两个原因引起变化。

三、桥接模式应用

  (1)电脑类型维度

 1 /**
 2  * 维度:电脑类型
 3  * @author CL
 4  *
 5  */
 6 public class Computer {
 7     protected Brand brand;
 8 
 9     public Computer(Brand brand) {
10         this.brand = brand;
11     }
12 
13     public void sale() {
14         brand.sale();
15     }
16 }
17 
18 /**
19  * 台式机
20  * @author CL
21  *
22  */
23 class Desktop extends Computer {
24 
25     public Desktop(Brand brand) {
26         super(brand);
27     }
28     
29     @Override
30     public void sale() {
31         super.sale();
32         System.out.println("销售台式机");
33     }
34 }
35 
36 /**
37  * 笔记本
38  * @author CL
39  *
40  */
41 class Laptop extends Computer {
42 
43     public Laptop(Brand brand) {
44         super(brand);
45     }
46     
47     @Override
48     public void sale() {
49         super.sale();
50         System.out.println("销售笔记本");
51     }
52 }
53 
54 /**
55  * 平板电脑
56  * @author CL
57  *
58  */
59 class Pad extends Computer {
60 
61     public Pad(Brand brand) {
62         super(brand);
63     }
64     
65     @Override
66     public void sale() {
67         super.sale();
68         System.out.println("销售平板电脑");
69     }
70 }

  (2)品牌维度

 1 /**
 2  * 一种维度:品牌
 3  * @author CL
 4  *
 5  */
 6 public interface Brand {
 7     void sale();
 8 }
 9 
10 /**
11  * 联想电脑
12  * @author CL
13  *
14  */
15 class Lenovo implements Brand {
16 
17     @Override
18     public void sale() {
19         System.out.println("销售联想电脑");
20     }
21     
22 }
23 
24 /**
25  * 戴尔电脑
26  * @author CL
27  *
28  */
29 class Dell implements Brand {
30 
31     @Override
32     public void sale() {
33         System.out.println("销售戴尔电脑");
34     }
35     
36 }
37 
38 /**
39  * 华硕电脑
40  * @author CL
41  *
42  */
43 class ASUS implements Brand {
44 
45     @Override
46     public void sale() {
47         System.out.println("销售华硕电脑");
48     }
49     
50 }

  (3)测试

 1 /**
 2  * 客户端
 3  * @author CL
 4  *
 5  */
 6 public class Client {
 7     
 8     public static void main(String[] args) {
 9         //销售联想笔记本电脑
10         Computer  c1 = new Laptop(new Lenovo());
11         c1.sale();
12         
13         //销售戴尔台式机
14         Computer c2 = new Desktop(new Dell());
15         c2.sale();
16     }
17 
18 }

  控制台输出:

销售联想电脑
销售笔记本
销售戴尔电脑
销售台式机

  (4)假如现在要在品牌维度上增加一种品牌:宏碁电脑,只需要在品牌维度中增加如下代码:

 1 /**
 2  * 宏碁电脑
 3  * @author CL
 4  *
 5  */
 6 class Acer implements Brand {
 7 
 8     @Override
 9     public void sale() {
10         System.out.println("销售宏碁电脑");
11     }
12     
13 }

  (5)测试

 1 /**
 2  * 客户端
 3  * @author CL
 4  *
 5  */
 6 public class Client {
 7     
 8     public static void main(String[] args) {
 9         //销售联想笔记本电脑
10         Computer  c1 = new Laptop(new Lenovo());
11         c1.sale();
12         
13         //销售戴尔台式机
14         Computer c2 = new Desktop(new Dell());
15         c2.sale();
16         
17         //销售宏碁的平板电脑
18         Computer c3 = new Pad(new Acer());
19         c3.sale();
20     }
21 
22 }

  控制台输出:

销售联想电脑
销售笔记本
销售戴尔电脑
销售台式机
销售宏碁电脑
销售平板电脑

四、桥接模式总结

  (1)桥接模式可以取代多层继承的方案。

      多层继承违背了单一职责原则,复用性较差,类的个数也非常多。桥接模式可以极大的减少子类的个数,从而降低管理和维护的成本。

  (2)桥接模式极大的提高了系统的可扩展性。

      在两个变化的维度中任意扩展一个维度。都不需要修改原有的代码,符合开闭原则。

五、桥接模式实际开发中的应用场景

  (1)JDBC驱动程序;

  (2)AWT中的Peer框架;

  (3)人力资源系统中的奖金计算模块:

      奖金分类:个人奖金、团队奖金、激励奖金

      部门分类:开发部门、运维部门、人事部门

  (4)OA系统中的消息处理:

      业务类型:普通消息、加密消息、紧急消息

      发送方式:系统内部、手机短信、邮件、飞秋

  (5)…………

 

posted @ 2018-01-18 16:39  C3Stones  阅读(270)  评论(0编辑  收藏  举报