• 桥接模式:探索JDBC的接口


    一、目录概要

    设计模式2

    二、问题探究

    需求:假设要设计一个电脑商场管理系统的某个模块设计,电脑分为品牌和类型两个纬度,我们应该怎么解决?

    按照初学者的思路,利用继承就能简单粗暴的实现,那我们来看下这种思路的设计类图。
    设计模式2

    从电脑纬度划分

    package com.aaron.bridge;
    
    public interface Computer {
        public void sale();
    }
    
    class Desktop implements Computer{
        @Override
        public void sale() {
            System.out.println("台式电脑");
        }
    }
    
    class Laptop implements Computer{
        @Override
        public void sale() {
            System.out.println("笔记本电脑");
        }
    }
    
    class Pad implements Computer{
        @Override
        public void sale() {
            System.out.println("平板电脑");
        }
    }
    

    从品牌纬度划分

    package com.aaron.bridge;
    // 宏碁品牌的三种类型
    public class AcerDesktop extends Desktop{
        @Override
        public void sale() {
            System.out.println("宏碁台式机");
        }
    }
    
    class AcerLaptop extends Laptop{
        @Override
        public void sale() {
            System.out.println("宏碁笔记本电脑");
        }
    }
    
    class AcerPad extends Pad{
        @Override
        public void sale() {
            System.out.println("宏碁平板电脑");
        }
    }
    
    package com.aaron.bridge;
    
    // 苹果品牌的三种类型
    public class AppleDesktop extends Desktop{
        @Override
        public void sale() {
            System.out.println("苹果台式机");
        }
    }
    
    class AppleLaptop extends Laptop{
        @Override
        public void sale() {
            System.out.println("苹果笔记本电脑");
        }
    }
    
    class ApplePad extends Pad{
        @Override
        public void sale() {
            System.out.println("苹果平板电脑");
        }
    }
    
    package com.aaron.bridge;
    
    //戴尔品牌的三种类型
    public class DellDesktop extends Desktop{
        @Override
        public void sale() {
            System.out.println("戴尔台式机");
        }
    }
    
    class DellLaptop extends Laptop{
        @Override
        public void sale() {
            System.out.println("戴尔笔记本电脑");
        }
    }
    
    class DellPad extends Pad{
        @Override
        public void sale() {
            System.out.println("戴尔平板电脑");
        }
    }
    
    

    问题1:假设我们的系统按照上述思路设计,当我们新增一个品牌的时候,怎么办?

    根据上述思路,从品牌纬度扩展品牌时直接新增台式机、笔记本电脑、平板电脑的类即可。

    问题2:当我们新增一个机器类型的时候又该怎么办?
    根据上述思路,在机器纬度类型扩展。

    1. 添加新的电脑机型。
    2. 在所有的品牌中,都新增新的机型。
    package com.aaron.bridge;
    
    // 电脑纬度
    public interface Computer {
        public void sale();
    }
    
    class Desktop implements Computer{
        @Override
        public void sale() {
            System.out.println("台式电脑");
        }
    }
    
    class Laptop implements Computer{
        @Override
        public void sale() {
            System.out.println("笔记本电脑");
        }
    }
    
    class Pad implements Computer{
        @Override
        public void sale() {
            System.out.println("平板电脑");
        }
    }
    
    class MaxPad implements Computer{
        @Override
        public void sale() {
            System.out.println("超大屏电脑");
        }
    }
    
    // 品牌纬度
    public class DellDesktop extends Desktop{
        @Override
        public void sale() {
            System.out.println("戴尔台式机");
        }
    }
    
    class DellLaptop extends Laptop{
        @Override
        public void sale() {
            System.out.println("戴尔笔记本电脑");
        }
    }
    
    class DellPad extends Pad{
        @Override
        public void sale() {
            System.out.println("戴尔平板电脑");
        }
    }
    
    class DellPad extends Pad{
        @Override
        public void sale() {
            System.out.println("戴尔平板电脑");
        }
    }
    
    class DellMaxPad extends Pad{
        @Override
        public void sale() {
            System.out.println("超大屏平板电脑");
        }
    }
    

    思考:当我们添加少量的机型和品牌的时候,该方案的代码扩展性还是可以接受的。但是,再往远思考一步。

    1. 假设电脑商城,添加10个品牌,再添加10种机型,怎么办?
    2. 系统已经上线,系统处于维护阶段人力有限,怎么办?

    问题:上述问题主要是把电脑和品牌两个纬度耦合。

    1. 违背单一职责原则(一个类只由一个维度影响)
    2. 违背开闭原则(对拓展开放,对修改关闭)。

    解决:将机器、品牌两个纬度进行拆分,不要将他们耦合。

    三、解决思路

    3.1 什么是桥接模式?

    将两个维度(抽象、实现)分离,使它们都可以独立地变化。

    3.2 桥接模式的分析
    1. 类型:台式机、笔记本电脑、平板电脑。
    2. 品牌:宏碁、苹果、戴尔。

    关键:将上述问题拆分成两个纬度类型和品牌。我们刚刚也讨论了,主要解决拓展性问题。当添加一个新的机器类型或者品牌的时候,不会对其他机器类型或者品牌产生影响。

    概念:简单谈下概念,重点根据类图和实现代码去理解Abstraction、RefinedAbstraction、Implementor、ConcreteImplementor

    Abstraction:抽象部分的接口。通常在这个对象里面,要维护一个实现部分的对象引用,在抽象对象里面的方法,需要调用实现部分的对象来完成。这个对象里面的方法,通常都是跟具体的业务相关的方法。

    RefinedAbstraction:
    扩展抽象部分的接口,通常在这些对象里面,定义跟实际业务相关的方法,这些方法的实现通常会使用Abstraction中定义的方法,也可能需要调用实现部分的对象来完成。

    Implementor:
    定义实现部分的接口,这个接口不用和Abstraction里面的方法一致(根据约定优于配置原则,建议跟Abstraction一致。),通常是由Implementor接口提供基本的操作,而Abstraction里面定义的是基于这些基本操作的业务方法,也就是说Abstraction定义了基于这些基本操作的较高层次的操作。

    ConcreteImplementor:
    真正实现Implementor接口的对象。

    设计模式2

    3.3 桥接模式实现

    1、实体部分设计

    package com.aaron.bridge;
    
    /**
     * 
     * @author xiaoyongAaron
     * 品牌纬度-实现部分接口
     */
    public interface ImplementorBrand {
        public void sale();
    }
    
    class  ConcreteImplementorAcer implements ImplementorBrand{
    
        @Override
        public void sale() {
            System.out.println("宏碁品牌");
        }
    }
    
    class ConcreteImplementorApple implements ImplementorBrand{
        @Override
        public void sale() {
            System.out.println("苹果品牌");
        }
    }
    
    class ConcreteImplementorDell implements ImplementorBrand{
        @Override
        public void sale() {
            System.out.println("戴尔品牌");        
        }
    }
    

    2、抽象部分设计

    package com.aaron.bridge;
    
    /**
     * 机器类型纬度-抽象部分
     * @author xiaoyongAaron
     */
    public class AbstractionComputer {
         protected ImplementorBrand brand;
              
         public AbstractionComputer(ImplementorBrand brand){
             this.brand=brand;
         }
         
         public void sale(){
            brand.sale(); 
         };
    
    }
    
    /**
     * 扩展部分
     * @author xiaoyongAaron
     */
    class RefinedAbstractionDesktop extends AbstractionComputer{
        public RefinedAbstractionDesktop(ImplementorBrand brand) {
            super(brand);
        }
    
        @Override
        public void sale() {
            //添加自己的特性,实际业务。
            paly();
            super.sale();
        }
        
        public void paly(){
            System.out.println("我台式机抗摔打");
        }
    }
    
    class RefinedAbstractionLaptop extends AbstractionComputer{
        public RefinedAbstractionLaptop(ImplementorBrand brand) {
            super(brand);
        }
    
        @Override
        public void sale() {
            //添加自己的特性,实际业务。
            lighting();
            super.sale();
        }
        
        public void lighting(){
            System.out.println("我笔记本电脑充电5分钟,续航5小时");
        }
    }
    
    class RefinedAbstractionPad extends AbstractionComputer{
        public RefinedAbstractionPad(ImplementorBrand brand) {
            super(brand);
        }
    
        @Override
        public void sale() {
            //添加自己的特性,实际业务。
            weighting();
            super.sale();
        }
        
        public void weighting(){
            System.out.println("我平板电脑便于携带");
        }
    }
    

    4、执行结果显示

    设计模式2

    四、问题回顾

    4.1 什么是桥接模式、为什么要桥接?

    简单说桥接模式就是把两个纬度分离,所以说当我们在实际开发的时候,遇到两个维度问题的时候,直接条件反射桥接模式。

    就像上述问题,当有两个维度(品牌+机器类型)赋予给一个类的时候,基于单一职责原则,需要把它们解耦。那通过上述范例可知,那么我们就需要一座桥一样,把两个纬度用一个中间物(类或者接口)把它们关联起来,从而达到我们的目的。

    4.2 桥接模式怎么接?

    核心:如何把Implementor对象传递到抽象接口。

    1. 如上述描述,利用构造函数传参。
    2. 创造无参构造函数,添加get、set方法。
    3. 工厂模式:参考设计模式的工厂模式。
    4. IOC控制反转,最经典的就是Spring容器。内部的实现原理原本创建对象都是由我们自己管理,但是把这一步骤交给容器管理,就不用我们担心了。例如在JDBC的设计当中,充当这个角色的就是DriverManage去把对象注入在抽象接口当中。
    4.3 桥接模式本质和经验
    1. 本质:抽象与实现(两个纬度)分离。
    2. 多用对象组合(has-A),少用继承。
    3. 开闭原则:我们应该对代码拓展开放,拒绝代码修改。

    实际应用场景:
    设计模式2

    作者:码农皮邱
    原文:https://www.cnblogs.com/qiuyong/p/6357839.html
    推荐:您的支持是对博主深入思考总结的最大鼓励,要是有需要关注公众号与作者面对面对话交流~
    说明:本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,尊重作者的劳动成果。

    微信公众号

    一直特立独行的二本僧,书写属于他的天空
  • 相关阅读:
    python两个装饰器的运算顺序
    python中私有属性的访问
    python中的方法使用
    创业,宁愿单兵作战也不要参在拙劣的团队里继续寻觅队友
    项目经理问:为什么总是只有我在加班 – 挂包袱现象
    我该怎么安排下属的工作-项目经理如何分配任务
    项目经理自己要写代码吗?
    管理系统书籍《从程序员到项目经理》 从程序员到项目经理(一)
    宗宁:赚快钱的那些坑。。(转载)
    java 实现二分法
  • 原文地址:https://www.cnblogs.com/qiuyong/p/6357839.html
Copyright © 2020-2023  润新知