桥接模式
标签 : Java与设计模式
场景
在商城系统中商品是分类摆放的,以电脑为例我们有以下商品分类, 该怎样良好的处理商品分类销售的问题:
直观上我们会觉得该商品分类以继承
来实现:电脑作为根类,台式机/笔记本/平板电脑作为其子类,联想台式机/…作为电脑的孙类.(其继承结构能够从图上直观的看出),可是考虑以下需求:
- 假设我们要添加一个品牌三星?
- 假设我们要添加一个分类智能手机?
问题1的解决方式是在台式机 笔记本 平板电脑 以下都加入对应的子类, 三星台式机 三星笔记本 ….
问题2的解决方式是需在电脑以下加入子类智能手机并在智能手机下在加入三个品牌分类联想智能手机 戴尔仅仅能手机 … 额,想想就够麻烦的,可是假设我们既要加入品牌又要加入分类呢? 要疯了…
这样下去导致的后果就是类的个数急速膨胀, 管理成本极高.
我们立即就意识到仅用继承的是不行的了:
对象的继承关系是在
编译
时就确定好了的,所以无法在执行时改变从父类继承的实现.子类的实现与他的父类有很紧密的依赖关系, 以至于父类实现中的不论什么变化必定会导致子类发生变化. 当你须要复用子类时,假设继承下来的实现不适合解决新的问题,则父类必须重写或被其它更适合的类替换.这样的依赖关系限制了灵活性并终于限制了复用性.
这个问题仅用继承是不能解决的,由于这样事实上是违反了单一职责原则
:一个类联想笔记本
,却有两个引起这个类变化的原因-类型维度
和品牌维度
.我们把两个维度混合在一起考虑,必定会造成牵一发而动全身的效果.
- 既然这样我们应该从两个维度来思考设计:
类型维度
有自己的一套继承结构,品牌维度
也有自己的一套继承结构,然后中间有座桥(Bridge)
把这两个类关联起来.这样在加入品牌时仅仅需在类型维度做改动就好了, 不会影响到品牌维度;当在品牌维度搞活动时,类型维度也不受影响.桥一端的变化不会引起还有一端的变化,这就是桥接模式
:
桥接模式
桥接模式: 将抽象部分与它的实现部分分离, 使他们都能够独立地变化.
事实上就是处理多层继承结构, 处理多维变化的场景, 将各个维度设计成独立地继承结构, 使得各个维度能够独立地扩展, 并在抽象层
建立关联.
注意, 这个结构的关键是: Abstraction
里面持有Implementor
对象.
这个反映到我们卖电脑的场景的类图关系例如以下:
Computer
的brand
属性就是那座桥
.
- 品牌维度
/**
* @author jifang
* @since 16/1/3下午6:25.
*/
public interface Brand {
String brand();
}
class Lenovo implements Brand {
@Override
public String brand() {
return "联想";
}
}
class Dell implements Brand {
@Override
public String brand() {
return "戴尔";
}
}
class Hasee implements Brand {
@Override
public String brand() {
return "神州";
}
}
- 类型维度
/**
* @author jifang
* @since 16/1/3下午6:33.
*/
public abstract class Computer {
private Brand brand;
public Computer(Brand brand) {
this.brand = brand;
}
public abstract String type();
public void sale() {
System.out.println("我们卖的是<" + brand.brand() + this.type() + ">电脑");
}
}
class Desktop extends Computer {
public Desktop(Brand brand) {
super(brand);
}
@Override
public String type() {
return "台式";
}
}
class Laptop extends Computer {
public Laptop(Brand brand) {
super(brand);
}
@Override
public String type() {
return "笔记本";
}
}
class Pad extends Computer {
public Pad(Brand brand) {
super(brand);
}
@Override
public String type() {
return "平板";
}
}
- Client
public class Client {
@Test
public void test() {
Computer computer = new Desktop(new Dell());
computer.sale();
}
}
如今我要新加一个智能手机类型, 那么仅仅需在Computer
以下加入一个Smartphone
即可了, 品牌维度不须要做不论什么的改动:
class Smartphone extends Computer {
public Smartphone(Brand brand) {
super(brand);
}
@Override
public String type() {
return "智能手机";
}
}
- Client
public class Client {
@Test
public void test() {
Computer computer = new Smartphone(new Lenovo());
computer.sale();
}
}
小结
- 桥接模式能够代替多层继承的方案. 多层继承违背了
单一职责原则
, 复用性较差, 类的个数过多. 桥接模式能够极大的降低子类的个数, 从而降低管理和维护的成本. - 桥接模式极大的提高了系统的可扩展性, 在两个变化维度中随意扩展一个维度, 都不须要改动原有的系统, 符合
开放-封闭原则
.
桥接模式在实际开发中应用场景:
- JDBC驱动程序
- AWT中的Peer架构
事实上仅仅要发现须要从多个角度去分类实现对象, 而仅仅用继承会造成大量类的添加,不能满足开放-封闭原则时,就应该考虑使用桥接模式.