具体实现Implementor接口,在不同的ConcreteImplementor中提供基本操作的不同实现,在程序运行时,ConcreteImplementor对象将替换其父类对象,提供给抽象类具体的业务操作方法。
**特点:**桥接模式中体现了“单一职责原则”、“开闭原则”、“合成复用原则”、“里氏代换原则”、“依赖倒转原则”等。
**技巧:**在使用桥接模式时,首先应该识别出一个类所具有的多个独立变化的维度,将它们设计为多个独立的继承等级结构,为多个维度都提供抽象层,并建立抽象耦合。通常情况下,我们将具有多个独立变化维度的类的一些普通业务方法和与之关系最密切的维度设计为“抽象类”层次结构(抽象部分),而将另一个维度设计为“实现类”层次结构(实现部分)。
使用场景
如果一个系统需要在抽象化和具体化之间增加更多的灵活性,避免在多个层次之间建立静态的继承关系,通过桥接模式可以使它们在抽象层建立一个关联关系。
“抽象部分”和“实现部分”可以以继承的方式独立扩展而互不影响,在程序运行时可以动态将一个抽象化子类的对象和一个实现化子类的对象进行组合,即系统需要对抽象化角色和实现化角色进行动态耦合。
一个类存在两个(或多个)独立变化的维度,且这两个(或多个)维度都需要独立进行扩展。
对于那些不希望使用继承或因为多层继承导致系统类的个数急剧增加的系统,桥接模式尤为适用。
程序猿实例
假设问题环境:
就拿程序猿编程来作为例子说明。程序猿既有移动开发攻城狮,也有服务器开发攻城狮,也有嵌入式开发攻城狮,他们可以使用Windows开发、也可以使用Linux开发,还可以使用MAC OS开发。这时你会发现对于程序猿来说他们有不同的类型,对于开发平台来说他们也有不同的类型。在软件系统中要适应两个方面(不同的程序猿和不的平台)的变化我们就需要动动脑袋了。
先看最顺手的继承方式代码实现:
看着下面代码你都会头疼,因为这才是二维的两种情况的组合,要是拓展就更加多代码和蛋疼了!
package yanbober.github.io;
class Platform {
public void program() {
System.out.println(“使用的平台!”);
}
}
class WindowsPlatform extends Platform {
@Override
public void program() {
System.out.println(“使用Windows平台!”);
}
}
class LinuxPlatform extends Platform {
@Override
public void program() {
System.out.println(“使用Linux平台!”);
}
}
class ServerWindowsPlatform extends WindowsPlatform {
@Override
public void program() {
System.out.println(“服务器攻城狮使用Windows平台!”);
}
}
class ServerLinuxPlatform extends LinuxPlatform {
@Override
public void program() {
System.out.println(“服务器攻城狮使用Linux平台!”);
}
}
class MobileWindowsPlatform extends WindowsPlatform {
@Override
public void program() {
System.out.println(“移动端攻城狮使用Windows平台!”);
}
}
class MobileLinuxPlatform extends LinuxPlatform {
@Override
public void program() {
System.out.println(“移动端攻城狮使用Linux平台!”);
}
}
public class Main {
public static void main(String[] args) {
ServerLinuxPlatform serverLinuxPlatform = new ServerLinuxPlatform();
serverLinuxPlatform.program();
ServerWindowsPlatform serverWindowsPlatform = new ServerWindowsPlatform();
serverWindowsPlatform.program();
MobileLinuxPlatform mobileLinuxPlatform = new MobileLinuxPlatform();
mobileLinuxPlatform.program();
MobileWindowsPlatform mobileWindowsPlatform = new MobileWindowsPlatform();
mobileWindowsPlatform.program();
}
}
升个级吧
上面代码可以发现,通过继承实现这种多维度变化类的数量太多,太乱,你拿前边的设计模式想想会发现它在遵循开放-封闭原则的同时,违背了类的单一职责原则,即一个类只有一个引起它变化的原因,而这里引起变化的原因却有两个;其次是重复代码会很多;再次是类的结构过于复杂,继承关系太多,难于维护,还有就是扩展性太差。
那么有没有好的办法,符合面向对象设计原则的方式呢?
当然有,就是使用桥接模式,如下展示:
package yanbober.github.io;
abstract class Platform {
protected Monkey mMonkey;
public abstract void program();
}
abstract class Monkey {
public abstract void type();
}
class WindowsPlatform extends Platform {
public WindowsPlatform(Monkey monkey) {
this.mMonkey = monkey;
}
@Override
public void program() {
mMonkey.type();
System.out.println(“使用Windows平台!”);
}
}
class LinuxPlatform extends Platform {
public LinuxPlatform(Monkey monkey) {
this.mMonkey = monkey;
}
@Override
public void program() {
mMonkey.type();
System.out.println(“使用Linux平台!”);
}
}
class ServerMonkey extends Monkey {
@Override
public void type() {
System.out.print(“服务器攻城狮”);
}
}
class MobileMonkey extends Monkey {
@Override
public void type() {
System.out.print(“移动端攻城狮”);
}
}
public class Main {
public static void main(String[] args) {
Monkey monkeyS = new ServerMonkey();
Monkey monkeyM = new MobileMonkey();
Platform platform = new WindowsPlatform(monkeyS);
platform.program();
platform = new WindowsPlatform(monkeyM);
platform.program();
platform = new LinuxPlatform(monkeyS);
platform.program();
platform = new LinuxPlatform(monkeyM);
platform.program();
}
}
如上实例通过对象的组合方式,使用桥接模式把两个角色之间的继承关系改为耦合关系,从而使这两者可以各自独立得变化,这特妹的就是桥接模式的真谛。但是你可能会说如上这样写增加了客户程序与平台和工程师的偶合关系。其实这种耦合是对象创建引起的,所以可以用创建型模式去解决。卧槽!!!这不就是设计模式真谛么?设计模式相互之间没有界限,没有完全的框架套用,需要灵活组建。
继续带你装逼带你飞的升级一把
玩完底端的二维度的变化以后咱们再来整点刺激的三维度,这下你就彻底明白为啥桥接模式比之前的继承好了,如下就是对现有程序猿使用平台的拓展,增加了所属公司。
package yanbober.github.io;
//新加的维度
abstract class Company {
protected Platform mPlatform;
public abstract void work();
}
//原有代码
abstract class Platform {
protected Monkey mMonkey;
public abstract void program();
}
abstract class Monkey {
public abstract void type();
}
class WindowsPlatform extends Platform {
public WindowsPlatform(Monkey monkey) {
this.mMonkey = monkey;
}
@Override
public void program() {
mMonkey.type();
System.out.println(“使用Windows平台!”);
}
}
class LinuxPlatform extends Platform {
public LinuxPlatform(Monkey monkey) {
this.mMonkey = monkey;
}
@Override
public void program() {
mMonkey.type();
System.out.println(“使用Linux平台!”);
}
}
class ServerMonkey extends Monkey {
@Override
public void type() {
System.out.print(“服务器攻城狮”);
}
}
class MobileMonkey extends Monkey {
@Override
public void type() {
System.out.print(“移动端攻城狮”);
}
}
写在最后
在技术领域内,没有任何一门课程可以让你学完后一劳永逸,再好的课程也只能是“师傅领进门,修行靠个人”。“学无止境”这句话,在任何技术领域,都不只是良好的习惯,更是程序员和工程师们不被时代淘汰、获得更好机会和发展的必要前提。
如果你觉得自己学习效率低,缺乏正确的指导,可以一起学习交流!
加入我们吧!群内有许多来自一线的技术大牛,也有在小厂或外包公司奋斗的码农,我们致力打造一个平等,高质量的Android交流圈子,不一定能短期就让每个人的技术突飞猛进,但从长远来说,眼光,格局,长远发展的方向才是最重要的。
35岁中年危机大多是因为被短期的利益牵着走,过早压榨掉了价值,如果能一开始就树立一个正确的长远的职业规划。35岁后的你只会比周围的人更值钱。
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可获取!