桥接模式学习

目录

  • 背景
  • 过程
  • 总结

背景

现在要解决源码阶段的继承关系,无法在运行时改变从父类继承的实现。这里用的是手机品牌还有手机中的app,这种问题如何进行解决呢。这就要引入一个模式:桥接模式

过程

1、原则:合成/复用原则 :尽量使用合成/聚合原则,不要使用类继承。
2、定义:将抽象部分和它的实现分离,使他们都可以独立变化。(不是说抽象类和实现类分离,实现指的是抽象类和它的派生类用来实现自己的对象。)

3、例子:

如手机品牌和手机app的关系,他们可以是继承关系,也可以是关联关系。

如果是继承关系的话,是对象的继承关系在编译的时候定义好了,无法在运行时改变从父类继承的实现。子类的视线和它的父类有很紧密的依赖关系,父类实现中的任何变化必然会导致子类发生变化。于是出现了这种聚合关系。

桥接模式学习_第1张图片

  1. Abstraction抽象类
public abstract class Abstraction {

    private Implementor imp;

    //约束子类必须实现该构造函数
    public Abstraction(Implementor imp) {
        this.imp = imp;
    }
    
    public Implementor getImp() {
        return imp;
    }

    //自身的行为和属性
    public void request() {
        this.imp.doSomething();
    }
    
}

  1. Implementor抽象类
public abstract class Implementor {

    public abstract void doSomething();
    public abstract void doAnything();
    
}

  1. ConcreteImplementor
public class ConcreteImplementorA extends Implementor {

    
    public void doSomething() {
        System.out.println("具体实现A的doSomething执行");
    }
    
    
    public void doAnything() {
        System.out.println("具体实现A的doAnything执行");
    }
}

  1. RefinedAbstraction
public class RefinedAbstraction extends Abstraction {

    //覆写构造函数
    public RefinedAbstraction(Implementor imp) {
        super(imp);
    }
    
    //修正父类行为
    
    public void request() {
        super.request();
        super.getImp().doAnything();
    }
    
}

  1. Client客户端
public class Client {

    public static void main(String[] args) {
        Implementor imp = new ConcreteImplementorA();
        Abstraction abs = new RefinedAbstraction(imp);
        abs.request();
    }
    
}

二、桥接模式的应用
1. 何时使用

系统可能有多个角度分类,每一种角度都可能变化时

2. 方法

把这种角度分类分离出来,让它们单独变化,减少它们之间的耦合(合成/聚合复用原则)

3. 优点

抽象和实现分离。桥梁模式完全是为了解决继承的缺点而提出的设计模式
优秀的扩展能力
实现细节对客户透明。客户不用关心细节的实现,它已经由抽象层通过聚合关系完成了封装

4. 缺点

会增加系统的理解与设计难度。由于聚合关联关系建立在抽象层,要求开发者针对抽象进行设计与编程

5. 使用场景

不希望或不适用使用继承的场景
接口或抽象类不稳定的场景
重用性要求较高的场景

6. 应用实例

开关。我们可以看到的开关是抽象的,不用管里面具体怎么实现
手机品牌与手机软件。两者间有一条聚合线,一个手机品牌可以有多个手机软件

7. 注意事项

不要一涉及继承就考虑该模式,尽可能把变化的因素封装到最细、最小的逻辑单元中,避免风险扩散
当发现类的继承有n层时,可以考虑使用该模式.

三、桥接模式的实现
下面我们举一个例子,就拿上面说的手机品牌与手机软件为例,我们可以让手机既可以按照手机品牌来分类,也可以按手机软件来分类。由于实现的方式有多种,桥接模式的核心意图就是把这些实现独立出来,让它们各自地变化,这就使得没中实现的变化不会影响其他实现,从而达到应对变化的目的。
桥接模式学习_第2张图片

  1. 手机品牌抽象类
public abstract class HandsetBrand {

    protected HandsetSoft soft;
    
    //设置手机软件
    public void setHandsetSoft(HandsetSoft soft) {
        this.soft = soft;
    }
    
    //运行
    public abstract void run();
    
}

  1. 手机软件抽象类
public abstract class HandsetSoft {

    public abstract void run();
    
}

  1. 各类手机品牌
public class HandsetBrandA extends HandsetBrand {

    
    public void run() {
        soft.run();
    }
    
}

  1. 各类手机软件
public class HandsetGame extends HandsetSoft {

    
    public void run() {
        System.out.println("运行手机游戏");
    }

}

5. Client客户端
public class Client {

    public static void main(String[] args) {
        HandsetBrand ab;
        
        //使用A品牌手机
        ab = new HandsetBrandA();
        System.out.println("A品牌手机:");
        
        ab.setHandsetSoft(new HandsetGame());
        ab.run();
        
        ab.setHandsetSoft(new HandsetAddressList());
        ab.run();
        
        //分隔符
        System.out.println("---------------");
        
        //使用B品牌手机
        ab = new HandsetBrandB();
        System.out.println("B品牌手机:");
        
        ab.setHandsetSoft(new HandsetGame());
        ab.run();
        
        ab.setHandsetSoft(new HandsetAddressList());
        ab.run();
    }
    
}

总结

这个桥接模式最深刻的一个点是:将源码定义好的关系修改为运行时在客户端中指定关系。解开源码定义好的类之间的耦合,变成运行的时候才让类之间耦合起来。

这样我现在如果想要增加一个功能,比如音乐播放器,那么只有增加这个类就可以了,不会影响到其他任何类,类的个数增加也只是一个;如果是要增加S品牌,只需要增加一个品牌的子类就可以了,个数也是一个,不会影响到其他类。这显然符合开放-封闭原则。
而这里用到的合成/聚合复用原则是一个很有用处的原则,即优先使用对象的合成或聚合,而不是继承。究其原因是因为继承是一种强耦合的结构,父类变,子类就必须变。

你可能感兴趣的:(设计模式,桥接模式,学习,java)