设计模式-桥接模式的实现[JAVA]

设计模式-桥接模式的实现[JAVA]

decouple an abstraction from its implementation so that the two can vary independently", introduced by the Gang of Four–翻译过来是:将抽象与实现解耦,以便让他们独立变化。直接理解起来确实比较难理解,我个人的理解偏像另一种表述“一个类存在两个或两个以上的独立变化的维度,然后通过组合的方式,让这两个或者多个维度上可以进行独立的扩展。”,个人对这个模式的理解就是控制变量法。一个维度依赖另一个维度的抽象,然后通过多态的方式把另一个维度的实现(以不变应万变。不变的是抽象,万变的是实现)。

引言

解释起来比较苍白,以一个实例来说明,桥接模式解决了那一类问题。
先看这么一个场景:
华为手机有Mate系列,有P系列。版本信息有30/40/50等。如果P30就是P系列中30版本。那么如何构建华为手机产品的类与类之间的关系了呢。通常的一种方式就是通过继承来实现。
如:手机<-华为手机<-P系列的华为手机<-p30版本的手机

具体实现如下:
类图:
在这里插入图片描述

代码:

/**
 * @Author: Shiraki
 * @Date: 2020/10/16 12:00
 */
public class SampleBridgeDemo {
    public static void main(String[] args) {
//        new PSerialPhone(new Version30()).call();
//        new PSerialPhone(new Version40()).call();
//        new MateSerialPhone(new Version30()).call();
//        new MateSerialPhone(new Version40()).call();
//        new HonorSerialPhone(new Version30()).call();
//        new HonorSerialPhone(new Version40()).call();
    }
}



/**
 * 手机抽象类
 */
abstract class Iphone {
    abstract void call();
}

/**
 * 版本接口
 */
interface IVersioner {
    String getVersion();
}


/**
 * 版本 30
 */
class Version30 implements IVersioner {

    @Override
    public String getVersion() {
        return "30";
    }
}

/**
 * 版本 40
 */
class Version40 implements IVersioner {

    @Override
    public String getVersion() {
        return "40";
    }
}

/**
 * 华为手机抽象类
 */
abstract class HuaweiPhone extends Iphone {
}

/**
 * 华为手机的修正类
 */
abstract class RefineHuiweiPhone extends HuaweiPhone {
    IVersioner iVersioner;
    // 注入实际版本类
    public RefineHuiweiPhone(IVersioner iVersioner) {
        this.iVersioner = iVersioner;
    }
}
/**
 * P系列类
 */
class PSerialPhone extends RefineHuiweiPhone{

    public PSerialPhone(IVersioner iVersioner) {
        super(iVersioner);
    }
    @Override
    void call() {
        System.out.println("Serial: P Version: " + iVersioner.getVersion());
    }
}

/**
 * 荣耀类
 */
class HonorSerialPhone extends RefineHuiweiPhone{

    public HonorSerialPhone(IVersioner iVersioner) {
        super(iVersioner);
    }
    @Override
    void call() {
        System.out.println("Serial: Honor Version: " + iVersioner.getVersion());
    }
}

class MateSerialPhone extends RefineHuiweiPhone {

    public MateSerialPhone(IVersioner iVersioner) {
        super(iVersioner);
    }
    @Override
    void call() {
        System.out.println("Serial: Mate Version: " + iVersioner.getVersion());
    }
}

以上我们通过继承方式构建了出来了华为手机之间的结构关系。
笔者是先通过先 维度-产品系列上做了分类,再在每个分类上又做了维度-版本的分类。那么这么做会有什么问题?

问题
如果要新增加一个版本:如 50版本。那么就要创建P50、Mate50、Honor50三个类;同理如果要增加一个产品系列Nova,那需要分别新增Nova30、Nova40、Nova50。增加的类比较多,而且集成深度也比较深。
如果用M表示系列的分类、用N表示版本的分类那么实际子类个数应该是M*N。
那么如何解决这个问题?
这时候就引入了桥接模式–就是为了解决直接集成导致的子类增长过快的问题。

追问
是什么原因导致使用继承会出现子类爆炸的问题
答案是:通过继承让维度-产品系列维度-产品版本解耦。也就是控制变量法,让其中的一个维度不变,再通过语言的动态性变动另一个维度。两维度关联依赖于抽象而非具体的实现。

桥接模式实现

标准类图如下:

来自维基百科
根据华为手机的例子,实现如下:
类图
在这里插入图片描述

具体思路是:HuaweiPhone是一个抽象类,再此基础上引入一个修正类RefineHuiweiPhone ,在抽象类RefineHuiweiPhone组合一个版本接口,然后具体的实现类继承修正类RefineHuiweiPhone即可,也就是对于维度-产品系列来说,并不关注版本信息,只是依赖于版本接口,同样维度-产品版本也不关心系列信息,只是通过抽象类去依赖抽象接口。从而实现维度与维度的解耦

使用桥接这种方式实现后子类个数应该是 M+N【用M表示系列的分类、用N表示版本的分类】
M*N > M+N,这就是桥接模式存在的意义。

代码

/**
 * @Author: Shiraki
 * @Date: 2020/10/16 12:00
 */
public class SampleBridgeDemo {
    public static void main(String[] args) {
//        new PSerialPhone(new Version30()).call();
//        new PSerialPhone(new Version40()).call();
//        new MateSerialPhone(new Version30()).call();
//        new MateSerialPhone(new Version40()).call();
//        new HonorSerialPhone(new Version30()).call();
//        new HonorSerialPhone(new Version40()).call();
    }
}



/**
 * 手机抽象类
 */
abstract class Iphone {
    abstract void call();
}

/**
 * 版本接口
 */
interface IVersioner {
    String getVersion();
}


/**
 * 版本 30
 */
class Version30 implements IVersioner {

    @Override
    public String getVersion() {
        return "30";
    }
}

/**
 * 版本 40
 */
class Version40 implements IVersioner {

    @Override
    public String getVersion() {
        return "40";
    }
}

/**
 * 华为手机抽象类
 */
abstract class HuaweiPhone extends Iphone {
}

/**
 * 华为手机的修正类
 */
abstract class RefineHuiweiPhone extends HuaweiPhone {
    IVersioner iVersioner;
    // 注入实际版本类
    public RefineHuiweiPhone(IVersioner iVersioner) {
        this.iVersioner = iVersioner;
    }
}
/**
 * P系列类
 */
class PSerialPhone extends RefineHuiweiPhone{

    public PSerialPhone(IVersioner iVersioner) {
        super(iVersioner);
    }
    @Override
    void call() {
        System.out.println("Serial: P Version: " + iVersioner.getVersion());
    }
}

/**
 * 荣耀类
 */
class HonorSerialPhone extends RefineHuiweiPhone{

    public HonorSerialPhone(IVersioner iVersioner) {
        super(iVersioner);
    }
    @Override
    void call() {
        System.out.println("Serial: Honor Version: " + iVersioner.getVersion());
    }
}

class MateSerialPhone extends RefineHuiweiPhone {

    public MateSerialPhone(IVersioner iVersioner) {
        super(iVersioner);
    }
    @Override
    void call() {
        System.out.println("Serial: Mate Version: " + iVersioner.getVersion());
    }
}

补充说明桥接模式的主要精髓实际上是 RefineHuiweiPhone修正类,他就像一个桥一样抽象了两个维度的变化。后续在 RefineHuiweiPhone的集成,实现类初始化的时候,每个维度都是互不影响。

总结

桥接模式其设计思想是通过组合来替换继承(依赖抽象而非实现),降低类的深度。通过将抽象(Abstraction)与实现(Implementor)分开,将它们放在单独的类层次结构中。使用控制变量法,以不变应万变。不变的是抽象,万变的是实现。

桥接模式相关问题

  1. 桥接模式和抽象工厂模式都是基于分类或者维度划分上衍生出来的设计模式,那么他们之间的区别是什么?
    桥接模式是结构型设计模式,主要描述类与类,产品与产品之间的关系,主要解决继承会导致子类爆炸的问题。
    抽象工厂是创建型设计模式,主要描述类与类,产品与产品之间增加分层,分类创建。主要解耦类对象的创建与使用,隐藏实际类对象的创建过程。两者侧重点不同。前置:用于类与类的关系结构设计,后者用于类依附于中间层进行分类创建的设计。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值