zoukankan      html  css  js  c++  java
  • 桥接模式:探索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
    推荐:您的支持是对博主深入思考总结的最大鼓励,要是有需要关注公众号与作者面对面对话交流~
    说明:本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,尊重作者的劳动成果。

    微信公众号

    一直特立独行的二本僧,书写属于他的天空
  • 相关阅读:
    Leetcode Spiral Matrix
    Leetcode Sqrt(x)
    Leetcode Pow(x,n)
    Leetcode Rotate Image
    Leetcode Multiply Strings
    Leetcode Length of Last Word
    Topcoder SRM 626 DIV2 SumOfPower
    Topcoder SRM 626 DIV2 FixedDiceGameDiv2
    Leetcode Largest Rectangle in Histogram
    Leetcode Set Matrix Zeroes
  • 原文地址:https://www.cnblogs.com/qiuyong/p/6357839.html
Copyright © 2011-2022 走看看