桥梁模式
例子
加入自己有两家公司,一家房地产公司只生产房子,一家山寨公司什么都可以生产。
public abstract class Corp {
private Product product;
public Corp(Product product) {
this.product = product;
}
public void makeMoney() {
this.product.beProducted();
this.product.beSelled();
}
}
public abstract class Product {
public abstract void beProducted();
public abstract void beSelled();
}
public class HouseCorp extends Corp{
public HouseCorp(House house) {
super(house);
}
@Override
public void makeMoney(){
super.makeMoney();
System.out.println("房地产公司赚大钱了...");
}
}
public class ShanZhaiCorp extends Corp{
public ShanZhaiCorp(Product product) {
super(product);
}
@Override
public void makeMoney(){
super.makeMoney();
System.out.println("我赚钱呀...");
}
}
public class House extends Product{
@Override
public void beProducted() {
System.out.println("生产出的房子是这样的...");
}
@Override
public void beSelled() {
System.out.println("生产出的房子卖出去了...");
}
}
public class IPod extends Product{
@Override
public void beProducted() {
System.out.println("生产出的iPod是这样的...");
}
@Override
public void beSelled() {
System.out.println("生产出的iPod卖出去了...");
}
}
public class Cloth extends Product{
@Override
public void beProducted() {
System.out.println("生产出的衣服是这样的...");
}
@Override
public void beSelled() {
System.out.println("生产出的衣服卖出去了...");
}
}
public class Client {
public static void main(String[] args) {
House house = new House();
System.out.println("-------房地产公司是这样运行的-------");
HouseCorp houseCorp = new HouseCorp(house);
houseCorp.makeMoney();
System.out.println("-------山寨公司是这样运行的-------");
ShanZhaiCorp shanZhaiCorp = new ShanZhaiCorp(new Cloth());
shanZhaiCorp.makeMoney();
}
}
HouseCorp类和ShanZhaiCorp类的区别是在有参构造的参数类型上,HouseCorp类比较明确,我就是只要House类,所以直接定义传递进来的必须是House类, 一个类尽可能少地承担职责,那方法也一样,既然HouseCorp类已经非常明确地只生产House产品,那为什么不定义成House类型呢?ShanZhaiCorp就不同了,它确定不了生产什么类型。
既然万物都是运动的,我现在只有房地产公司和山寨公司,那以后我会不会增加一些 其他的公司呢?或者房地产公司会不会对业务进行细化,如分为公寓房公司、别墅公司,以及商业房公司等。
这种变化对我们上面 的类图来说不会做大的修改,充其量只是扩展:
- 增加公司,要么继承Corp类,要么继承HouseCorp或ShanZhaiCorp,不用再修改原有的类了。
- 增加产品,继承Product类,或者继承House类,你要把房子分为公寓房、别墅、商业用房等。
你唯一要修改的就是Client类。类都增加了,高层模块也需要修改,也就是说Corp类和Product类都可以自由地扩展,而不会对整个应用产生太大的变更,这就是桥梁模式。
定义
将抽象和实现解耦,使得两者可以独立地变化。
- Abstraction——抽象化角色
它的主要职责是定义出该角色的行为,同时保存一个对实现化角色的引用,该角色一般是抽象类。 - Implementor——实现化角色
它是接口或者抽象类,定义角色必需的行为和属性。 - RefinedAbstraction——修正抽象化角色
它引用实现化角色对抽象化角色进行修正。 - ConcreteImplementor——具体实现化角色
它实现接口或抽象类定义的方法和属性。
public interface Implementor {
void doSomething();
void doAnything();
}
public class ConcreteImplementor1 implements Implementor{
@Override
public void doSomething() {
}
@Override
public void doAnything() {
}
}
public class ConcreteImplementor2 implements Implementor{
@Override
public void doSomething() {
}
@Override
public void doAnything() {
}
}
public abstract class Abstraction {
private Implementor imp;
public Abstraction(Implementor imp) {
this.imp = imp;
}
public void request(){
this.imp.doSomething();
}
public Implementor getImp(){
return this.imp;
}
}
public class RefinedAbstraction extends Abstraction{
public RefinedAbstraction(Implementor imp) {
super(imp);
}
@Override
public void request(){
super.request();
super.getImp().doAnything();
}
}
public class Client {
public static void main(String[] args) {
ConcreteImplementor1 imp = new ConcreteImplementor1();
RefinedAbstraction abs = new RefinedAbstraction(imp);
abs.request();
}
}
桥梁模式是一个非常简单的模式,它只是使用了类间的聚合关系、继承、覆写等常用功能,但是它却提供了一个非常清晰、稳定的架构。
优点
- 抽象和实现分离
这也是桥梁模式的主要特点,它完全是为了解决继承的缺点而提出的设计模式。在该模式下,实现可以不受抽象的约束,不用再绑定在一个固定的抽象层次上。 - 优秀的扩充能力
看看我们的例子,想增加实现?没问题!想增加抽象,也没有问题!只要对外暴露的接口层允许这样的变化,我们已经把变化的可能性减到最小。 - 实现细节对客户透明
客户不用关心细节的实现,它已经由抽象层通过聚合关系完成了封装。
使用场景
- 不希望或不适用使用继承的场景
例如继承层次过渡、无法更细化设计颗粒等场景,需要考虑使用桥梁模式。 - 接口或抽象类不稳定的场景
明知道接口不稳定还想通过实现或继承来实现业务需求,那是得不偿失的,也是比较失 败的做法。 - 重用性要求较高的场景
设计的颗粒度越细,则被重用的可能性就越大,而采用继承则受父类的限制,不可能出现太细的颗粒度。
注意
桥梁模式的意图还是对变化的封装,尽量把可能变化的因素封装到最细、最小的逻辑单元中,避免风险扩散。因此读者在进行系统设计时,发现类的继承有N层时,可以考虑使用桥梁模式。