桥接模式

场景

​ 商城系统中常见的商品分类,以电脑为例,如何良好的处理商品分类销售的问题?我们可以用多层继承实现下图的关系:

图1

代码实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public interface Computer {
void sale();
}
class Desktop implements Computer{
@Override
public void sale() {
System.out.println("销售台式电脑");
}
}
class Laptop implements Computer{
@Override
public void sale() {
System.out.println("销售笔记本电脑");
}
}
class LenovoDesktop extends Desktop{
@Override
public void sale() {
System.out.println("销售联想台式电脑");
}
}
class LenovoLaptop extends Laptop{
@Override
public void sale() {
System.out.println("销售联想笔记本电脑");
}
}
class DellDesktop extends Desktop{
@Override
public void sale() {
System.out.println("销售戴尔台式电脑");
}
}
class DellLaptop extends Laptop{
@Override
public void sale() {
System.out.println("销售戴尔笔记本电脑");
}
}

这样实现的问题:

  • 拓展性问题:
    1. 如果要增加新的电脑类型:如平板电脑,则要增加各个品牌下面的类。
    2. 如果要新增品牌,也要新增各个电脑下的类。
  • 违反单一职责原则:一个类:如联想笔记本电脑,有两个引起这个类变化的原因:品牌及电脑类型。

​ 所以,某些类型由于自身的逻辑,它具有两个或多个维度的变化,为了应对这种“多维度的变化“,并且利用面向对象的技术来使得该类型能够轻松的沿着多个方向进行变化,而又不引入额外的复杂度。这就要使用Bridge模式。

桥接模式

意图

​ 把抽象(abstraction)与行为实现(implementation)分离开来,从而可以保持各部分的独立性以及应对它们的功能扩展。

结构图

图1

实现代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* 电脑品牌维度接口
*/
public interface Brand {
void name();
}

class Lenovo implements Brand{
@Override
public void name() {
System.out.println("联想电脑");
}
}

class Dell implements Brand{
@Override
public void name() {
System.out.println("戴尔电脑");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/**
* 电脑类型维度
*/
public class Computer{
protected Brand brand;
public Computer(Brand brand){
this.brand=brand;
}
public void sale(){
brand.name();
}
}
class Desktop extends Computer{
public Desktop(Brand brand) {
super(brand);
}
@Override
public void sale() {
super.sale();
System.out.println("销售台式机");
}
}

class Laptop extends Computer{
public Laptop(Brand brand) {
super(brand);
}
@Override
public void sale() {
super.sale();
System.out.println("销售笔记本");
}
}
1
2
3
4
5
6
7
8
9
/**
* 客户端
*/
public class Client {
public static void main(String[] args) {
Computer len=new Desktop(new Lenovo());
len.sale();
}
}

​ 这样就很好的将电脑品牌和电脑类型两个维度分离开并且组合使用,这样在增加品牌或类型都更加简单。

设计要点

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

使用场景

  1. 如果一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的联系。
  2. 设计要求实现化角色的任何改变不应当影响客户端,或者说实现化角色的改变对客户端是完全透明的。
  3. 一个构件有多于一个的抽象化角色和实现化角色,系统需要它们之间进行动态耦合。
  4. 虽然在系统中使用继承是没有问题的,但是由于抽象化角色和具体化角色需要独立变化,设计要求需要独立管理这两者

本文转载自:Java设计模式学习07——桥接模式