精华内容
下载资源
问答
  • 设计模式之桥接模式

    2017-12-07 16:11:13
    设计模式之桥接模式 设计模式之桥接模式 设计模式之桥接模式
  • 桥接模式

    万次阅读 2020-12-26 10:19:56
    桥接模式桥接模式是将抽象部分与它的实现部分分离,使它们都可以独立地变化。它是一种对象结构型模式, 又称为柄体(Handle and Body)模式或接口(Interfce)模式。 传统多继承结构 桥接模式 //品牌 public ...

    桥接模式

    ◆桥接模式是将抽象部分与它的实现部分分离,使它们都可以独立地变化。它是一种对象结构型模式, 又称为柄体(Handle and Body)模式或接口(Interfce)模式。

    传统多继承结构
    在这里插入图片描述
    桥接模式
    在这里插入图片描述

    //品牌
    public interface Brand {
        void info();
    }
    
    
    
    //联想品牌
    public class Lenovo implements Brand{
        @Override
        public void info() {
            System.out.println("联想");
        }
    }
    
    
    //苹果品牌
    public class Apple implements Brand{
        @Override
        public void info() {
            System.out.println("苹果");
        }
    }
    
    
    //抽象的电脑类型
    public class Computer {
        //组合品牌
        protected Brand brand;
        public Computer(Brand brand) {
            this.brand = brand;
        }
        public void info(){
        brand.info(); //再带品牌
        }
    }
    class Desktop extends Computer{
    
        public Desktop(Brand brand) {
            super(brand);
        }
        @Override
        public void info(){
            super.info();
            System.out.println("台式机");
        }
    }
    
    class Laptop extends Computer{
    
        public Laptop(Brand brand) {
            super(brand);
        }
        @Override
        public void info(){
            super.info();
            System.out.println("笔记本");
        }
    }
    
    
    public class Test {
        public static void main(String[] args) {
            // 苹果笔记本
            Computer computer = new Laptop(new Apple());
            computer.info();
            //联想台式机
    
            Computer computer1 = new Desktop(new Lenovo());
            computer1.info();
        }
    }
    
    

    在这里插入图片描述
    ◆好处分析:

    • 桥接模式偶尔类似于多继承方案,但是多继承方案违背了类的单一职责原则,复用性比较差, .类的个数也非常多,桥接模式是比多继承方案更好的解决方法。极大的减少了子类的个数,从而降低管理和维护的成本
    • 桥接模式提高了系统的可扩充性,在两个变化维度中任意扩展一个维度, 都不需要修改原有系统。符合开闭原则,就像: - -座桥,可以把两个变化的维度连接起来!

    ◆劣势分析:

    • 桥接模式的引入会增加系统的理解与设计难度,由于聚合关联关系建立在抽象层,要求开发者针对抽象进行设计与编程。
    • 桥接模式要求正确识别出系统中两个独立变化的维度,因此其使用范围具有一定的局限性。

    最佳实践:

    • 如果一个系统需要在构建的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的继承联系,通过桥接模式可以使它们在抽象层建立-个关联关系。抽象化角色和实现化角色可以以继承的方式独立扩展而互不影响,在程序运行时可以动态将一个抽象化子类的对象和一 个实现化子类的对象进行组合,即系统需要对抽象化角色和实现化角色进行动态耦合。
    • 一个类存在两个独立变化的维度, 且这两个维度都需要进行扩展。
    • 虽然在系统中使用继承是没有问题的,但是由于抽象化角色和具体化角色需要独立变化,设计要求需要独立管理这两者。对于那些不希望使用继承或因为多层次继承导致系统类的个数急剧增加的系统,桥接模式尤为适用。

    场景:
    ◆Java语言通过Java虚拟机实现了平台的无关性。
    ◆AWT中的Peer架构
    ◆JDBC驱动程序也是桥接模式的应用之一。

    展开全文
  • 桥接模式-概念、实现及JDBC中的桥接模式1、概念2、实现3、JDBC中的桥接模式4、思考 1、概念 桥接模式(Bridge Pattern)也称桥梁模式 定义:将抽象部分与实现部分分离,使它们可以独立地进行定义。 多维度的变化类...

    学习设计模式不光要学习设计模式的思想,还要去深入理解,为什么要用这个设计模式。
    如何深入理解?读优秀的框架代码,看别人代码,了解它们的使用场景。 - - - 博主老师(感谢他)

    本文先介绍了桥接模式的概念及简单实现。再介绍了JDBC中对桥接模式的实现。

    桥接模式-概念、实现及JDBC中的桥接模式

    1、概念

    桥接模式(Bridge Pattern)也称桥梁模式
    定义:将抽象部分与实现部分分离,使它们可以独立地进行定义。

    多维度的变化类或者说多个树状类之间的耦合都可以用桥接模式来实现解耦。

    似乎还有点模糊…直接看实现就能理解了。

    2、实现

    考虑这么一个例子:咖啡馆的咖啡分为:大杯加糖、大杯不加糖、小杯加糖、小杯不加糖
    咖啡类

    public abstract class Coffee {
    
        protected CoffeeAdditives impl;
    
        public Coffee(CoffeeAdditives impl) {
            this.impl = impl;
        }
    
        public abstract void makeCoffee();
    }
    
    

    咖啡添加物

    public abstract class CoffeeAdditives {
    
        public abstract String addSomething();
    }
    

    大杯咖啡

    public class LargeCoffee extends Coffee {
    
        public LargeCoffee(CoffeeAdditives impl) {
            super(impl);
        }
    
        @Override
        public void makeCoffee() {
            System.out.println("大杯的" + impl.addSomething() + "咖啡");
        }
    }
    

    小杯咖啡

    public class SmallCoffee extends Coffee {
        public SmallCoffee(CoffeeAdditives impl) {
            super(impl);
        }
    
        @Override
        public void makeCoffee() {
            System.out.println("小杯的" + impl.addSomething() + "咖啡");
        }
    }
    

    添加剂:糖

    public class Sugar extends CoffeeAdditives {
        @Override
        public String addSomething() {
            return "加糖";
        }
    }
    

    添加剂:无

    public class Ordinary extends CoffeeAdditives {
        @Override
        public String addSomething() {
            return "不加糖";
        }
    }
    

    测试类

    public static void main(String[] args) {
        Ordinary ordinary = new Ordinary();
        Sugar sugar = new Sugar();
    
        Coffee largeCoffeeOrdinary = new LargeCoffee(ordinary);
        largeCoffeeOrdinary.makeCoffee();
    
        Coffee smallCoffeeOrdinary = new SmallCoffee(ordinary);
        smallCoffeeOrdinary.makeCoffee();
    
        Coffee largeCoffeeSugar = new LargeCoffee(sugar);
        largeCoffeeSugar.makeCoffee();
    
        Coffee smallCoffeeSugar = new SmallCoffee(sugar);
        smallCoffeeSugar.makeCoffee();
    }
    
    

    输出

    大杯的不加糖咖啡
    小杯的不加糖咖啡
    大杯的加糖咖啡
    小杯的加糖咖啡
    

    我们先定义了咖啡类,实现了大杯小杯。再定义了一个咖啡添加物类,实现了加糖和不加糖。其中,在咖啡中与添加物做了绑定。这里抽象部分是添加物,实现部分是咖啡。咖啡是被调用者,添加物是主动方。

    3、JDBC中的桥接模式

    我们知道jdbc只提出了一系列接口规范,具体的实现由数据库提供者去实现。所以,当我们在连接mysql的时候,需要添加jdbc-mysql.jar,在连接oracel的时候,需要添加ojdbc.jar(不确定jar名有没有写错,没在代码里用过oracel)。然后去载入驱动,再进行连接

    // 使用
    Class.forName("com.mysql.jdbc.Driver");
    Connection conn= DriverManager.getConnection(url,user,password);
    

    com.mysql.jdbc.Driver 源码

    import java.sql.DriverManager;
    import java.sql.SQLException;
    
    public class Driver extends NonRegisteringDriver implements java.sql.Driver {
        public Driver() throws SQLException {
        }
    
        static {
            try {
                DriverManager.registerDriver(new Driver());
            } catch (SQLException var1) {
                throw new RuntimeException("Can't register driver!");
            }
        }
    }
    

    Class.forName会把类加载进来,执行类的静态方法(类加载的初始化阶段)。我们看到mysql Driver的static块,调用了java.sql.DriverManager的registerDriver方法。

    public class DriverManager {
        public static synchronized void registerDriver(java.sql.Driver driver) throws SQLException {
            registerDriver(driver, null);
        }
        public static synchronized void registerDriver(java.sql.Driver driver, DriverAction da) throws SQLException {
            /* Register the driver if it has not already been added to our list */
            if(driver != null) {
                registeredDrivers.addIfAbsent(new DriverInfo(driver, da));
            } else {
                // This is for compatibility with the original DriverManager
                throw new NullPointerException();
            }
        
            println("registerDriver: " + driver);
       }
        
    }
    
    

    我们分析下,这里和桥接模式有什么关系。
    回顾一下桥接模式的定义:将抽象部分与实现部分分离,使它们可以独立地进行定义。 为两个独立变化的维度设计两个独立的继承等级结构,并在抽象层建立一个抽象关联。
    这里两个独立变化的维度:

    1. 数据库驱动
    2. 应用程序的数据库连接信息(可能是mysql,可能是oracel等)

    对于应用程序而言,只要选用不同的驱动,就可以让程序操作不同的数据库,而无需更改应用程序,从而实现在不同的数据库上移植;
    对于驱动程序而言,为数据库实现不同的驱动程序,并不会影响应用程序

    4、思考

    一个类存在两个独立变化的维度,且这两个维度都需要进行扩展。可以考虑桥接模式。在设计系统的时候,尤其是对外开放的系统,一定要考虑这种变化可能带来的影响。以前没注意过这个jdbc的实现,粗浅得了解了下,真佩服啊…
    设计模式的学习不要拘泥于局部代码,要从整体去把握。


    [1] https://blog.csdn.net/paincupid/article/details/43614029

    展开全文
  • 主要介绍了C++设计模式之桥接模式,本文讲解了什么是桥接模式、为什么要使用桥接模式、什么时候使用桥接模式等内容,需要的朋友可以参考下
  • 桥接模式-设计模式

    2013-07-27 14:39:35
    桥接模式 桥接模式
  • 桥接模式源码

    2019-02-18 13:26:47
    桥接模式模拟,源代码,多种对比方式,桥接模式简单实现
  • 一.VMware设置桥接模式 1.VMware -> 编辑->虚拟网络编辑器->更改设置 选择VMnet0(桥接模式),选择与主机同名网卡 ,主机可在在网络中心查看网卡名称 2.设置桥接模式  选择桥接...

    一.VMware设置桥接模式

    1.VMware -> 编辑->虚拟网络编辑器->更改设置

    选择VMnet0(桥接模式),选择与主机同名网卡 ,主机可在在网络中心查看网卡名称

    2.设置桥接模式 

    选择桥接模式 

    二.解决上不了网的问题

    0、在vmware虚拟机中:vmnet0对应桥接模式;vmnet1对应NAT模式;vmnet8对应仅主机模式。

    安装vmware后,在网络适配器中会多出vmnet1和vmnet8两个网络适配器。

    1、查看本地连接

    (1)属性中是否有“VMware Bridge Protocol”选项。如果没有,需要通过 安装——服务——添加——从磁盘安装——浏览——选择VMware安装目录下的netbridge.inf——确定——确定 来安装。安装后就会出现。

    (2)该选项是否为选中状态,如果未选中,请选中。

     

    2、查看vmware:编辑——虚拟网络编辑器——更改设置

    (1)是否同时有VMnet0 VMnet1 VMnet8,且和文首的对应关系相符(当然桥接网络只会用到VMnet0)。如果不相符,点击“还原默认设置”按钮,将设置还原,还原后就会只剩下上述三个选项。

    (2)选中VMnet0,在下方的“桥接到”选项框中,默认选择的是“自动”。如果只有一个网卡,可不用选择。如果有多个网卡,最好手动选择一个希望桥接到的主机电脑的网络适配器名称。

    (3)确保“桥接到”选项框中出现的主机电脑的网络适配器名称是正确的,如果不正确,看看是否有其他wifi设备未设置正确。

    3、查看目标虚拟机:设置——网络适配器——选择桥接模式

    2和3就是一.设置桥接模式

     

    4.本人在安装完CentOS7后设置桥接模式不知道为什么不能上外网

    在图形界面打开网络连接,删除配置

    再重新设置

    当然也可以用纯命令行设置

    1.备份网络配置

    cd到/etc/sysconfig/network-scripts 目录

    cd /etc/sysconfig/network-scripts
    

    查看该目录下的文件,ifcfg-eth0(这是我centOS7改名后的文件名 ,centOS7我安装后一开始是ifcfg-eno33)

    备份配置文件

    cp ifcfg-eth0 ifcfg-eth0.backup
    

    2.打开配置文件,编辑保存

    vi ifcfg-eth0

    在命令模式下输入i进入插入模式编辑 

    HWADDR=00:0C:29:E1:73:78
    TYPE=Ethernet
    PROXY_METHOD=none
    BROWSER_ONLY=no
    BOOTPROTO=static       #static,静态ip,而不是dhcp,自动获取ip地址
    DEFROUTE=yes
    IPV4_FAILURE_FATAL=no
    IPV6INIT=yes
    IPV6_AUTOCONF=yes
    IPV6_DEFROUTE=yes
    IPV6_FAILURE_FATAL=no
    IPV6_ADDR_GEN_MODE=stable-privacy
    NAME=eth0              #虚拟网卡名
    UUID=d6b36c63-6d8b-3e84-8c2c-1e284b831773
    ONBOOT=yes             #开机启用网络配置。
    AUTOCONNECT_PRIORITY=-999
    DNS1=8.8.8.8           #谷歌DNS
    DNS2=8.8.8.4                    
    IPADDR=192.168.0.104   #设置我想用的静态ip地址,要和物理主机在同一网段,但又不能相同
    PREFIX=24              #子网掩码即(255.255.255.0),和物理主机一样就可以了
    GATEWAY=192.168.0.1    #网关和物理主机一样
    

    修改完按Esc进入命令模式,按shift+:    输入wq保存退出

    3.重启服务

    service network  restart

     

    5.虚拟机ping不通主机原因

    简单方式:关闭主机的防火墙,即可

    方式二:

    win10的宿主机:windows防火墙-高级设置-入站规则-虚拟机监控(回显请求-ICMPv4-In)。

    把这项给启用了就可以了。如果网络是在公用,则需要去属性-高级 勾选公用

    展开全文
  • Bridge桥接模式

    2019-02-24 13:57:54
    Bridge桥接模式 文章目录Bridge桥接模式前言模式定义与继承比较桥接模式关系梳理模式结构总结感谢 前言 关于桥接模式我有以下几个问题想问: 什么是桥接模式? 为什么需要桥接模式(也就是什么情况下使用桥接模式...

    Bridge桥接模式



    前言

    关于桥接模式我有以下几个问题想问:

    • 什么是桥接模式?
    • 为什么需要桥接模式(也就是什么情况下使用桥接模式)?
    • 桥接模式的优点是什么?
    • 桥接模式的缺点是什么?

    桥接模式与装饰模式很相似,然而,桥接模式主要是为了应对“多维度变化”。同时,桥接模式的使用场景存在一定的局限性。

    模式定义

    在《设计模式》一书中,对桥模式做了如下释义:

    将抽象部分与实现部分分离,使它们都可以独立变化。

    GoF这句话的意思是,桥模式能够让抽象部分与实现部分独立变化。这显然是一个解耦的过程,同时,需要两个维度的存在(抽象部分和实现部分)——这是因为,只有存在多个维度时,才有每个维度都可以独立变化的需求。

    与继承比较

    现在,假设我们需要做一个QQ这样的软件,它包括登陆,发送消息,画图与播放音乐这些功能。因此,抽象基类可以设计成如下样子:

    class QQ {
    public:
    	virtual void login()=0;
    	virtual void sendmsg()=0;
    
    	virtual void music()=0;
    	virtual void draw()=0;
    
    	virtual ~QQ(){};
    };
    

    众所周知,QQ能够安装在win上,也可以在苹果电脑上安装。基于不同设备,它们在播放音乐、画图功能上存在实现差别是理所当然的(例如不同浏览器对css的支持不尽相同)。所以,不同平台,不同实现:

    class WinQQ: public QQ {
    public:
    	virtual void music() {
    		// win播放音乐的操作
    	}
    	virtual void draw() {
    		// win画图的操作
    	}
    };
    
    class AppleQQ: public QQ {
    	virtual void music() {
    		// apple播放音乐的操作
    	}
    	virtual void draw() {
    		// apple画图的操作
    	}
    };
    

    依照现实情况,腾讯旗下的QQ其实有两种,一种是完整版的QQ(把它叫作 QQPerfect 吧),另一种是精简版的TIM。或许在登陆过程中,QQPerfect需要播放音乐而TIM为了足够简洁则不允许播放音乐;在发送消息上,QQPerfect能够发送用户自己画出来的图(draw()产生的数据),TIM则不可以。两种版本的QQ都应该得到win和apple平台的支持。

    class WinQQPerfect: WinQQ {
    public:
    	virtual void login() {
    		WinQQ::music();
    		// 登陆逻辑
    	}
    	virtual void sendmsg() {
    		...
    		if (...) {
    			WinQQ::draw();
    			// 发送逻辑
    		}
    	}
    };
    
    class WinTim: WinQQ {
    public:
    	virtual void login() {
    		// 登陆逻辑
    	}
    	virtual void sendmsg() {
    		// 发送逻辑
    	}
    };
    
    ...  // 省略AppleQQPerfect,AppleTim的代码
    

    事实上,WinQQPerfect与AppleQQPerfect,以及WinTim与AppleTim,无非是平台不同,以至于继承的父类不同(前者继承WinQQ,后者继承AppleQQ),我们可以利用组合的方式合并这些类。此时需要对QQ这个抽象基类做些改动:

    class QQ {  // 改动后的QQ
    protected:
    	QQ* qq;
    public:
    	QQ(QQ* qq): qq(qq) {}
    	virtual void login()=0;
    	virtual void sendmsg()=0;
    
    	virtual void music()=0;
    	virtual void draw()=0;
    
    	virtual ~QQ(){};
    };
    
    class QQPerfect: public QQ {  // 合并后的QQPerfect
    public:
    	QQPerfect(QQ* qq): QQ(qq) {}
    	virtual void login() {
    		qq->music();
    		// 登陆逻辑
    	}
    	virtual void sendmsg() {
    		...
    		if (...) {
    			qq->draw();
    			// 发送逻辑
    		}
    	}	
    };
    
    ...  // 省略TIM的代码
    

    合并WinQQPerfect与AppleQQPerfect之后,麻烦也随之而来,这是因为如果现在实例化一个win版本的QQPerfect,需要这样:

    WinQQ wqq = new WinQQ();  // 基类不可以被实例化
    QQPerfect wqpft = new QQPerfect(wqq);
    

    可是不行,因为WinQQ继承自抽象基类QQ,而QQ包含了登陆、发送消息、音乐、画图四个纯需函数,WinQQ仅仅重写了music()draw()。也就是说,它还继承了父类的login()sendmsg()两个纯需函数,WinQQ现在是一个抽象基类,不可以被实例化。

    那我们在QQ类中实现登陆、发送消息两个功能可以吗?显然不行,因为完整版的QQPerfect与TIM的登陆细节不同。对WinQQ来说,亦是同样道理。

    由此,陷入一种僵局状态…

    桥接模式

    回到最初的起点,整理一下思路。基类QQ有四个纯需函数:登陆,发送,音乐,画图。现在我们有两个需求,一个平台相关(Win、Apple),一个业务相关(QQPerfect、TIM)。画图音乐是平台相关,登陆发送是业务相关,平台与业务是两个维度,可我们将其设计在一个类中,看上去这不合理。

    桥接模式认为,它们应该分手。原有的QQ于是一分为二,一个专注业务叫QQ,一个专注平台叫QQPlatform:

    class QQ {
    protected:
    	QQPlatform* platform;
    public:
    	QQ(QQPlatform* plt): platform(plt);
    	virtual void login()=0;
    	virtual void sendmsg()=0;
    };
    
    class QQPlatform {
    public:
    	virtual void music()=0;
    	virtual void draw()=0;
    };
    

    这样一来,平台基于QQPlatform:

    class WinQQ: public QQPlatform {
    public:
    	virtual void music() {
    		// win播放音乐的操作
    	}
    	virtual void draw() {
    		// win画图的操作
    	}
    };
    
    class AppleQQ: public QQPlatform {
    	virtual void music() {
    		// apple播放音乐的操作
    	}
    	virtual void draw() {
    		// apple画图的操作
    	}
    };
    

    业务基于QQ:

    class QQPerfect: public QQ {
    public:
    	QQPerfect(QQPlatform* plt): QQ(plt) {}
    	virtual void login() {
    		plt->music();
    		// 登陆逻辑
    	}
    	virtual void sendmsg() {
    		...
    		if (...) {
    			plt->draw();
    			// 发送逻辑
    		}
    	}
    };
    
    class Tim: public QQ {
    public:
    	QQPerfect(QQPlatform* plt): QQ(plt) {}
    	virtual void login() {
    		// 登陆逻辑
    	}
    	virtual void sendmsg() {
    		// 发送逻辑
    	}
    }
    

    现在,平台与业务可以随意组合了:

    // win上的完整版QQ
    WinQQ* wqq = new WinQQ();
    QQPerfect* wqpft = new QQPerfect(wqq);
    
    // apple上的TIM
    AppleQQ* aqq = new AppleQQ();
    Tim* tim = new Time(aqq);
    
    ...
    

    也许不论是完整的QQ还是TIM,其中的登陆逻辑与发送逻辑应该相同,区别在于login()sendmsg()中的其他部分(放音乐或是发送画图数据)。虽说如此,但我仍没有直接在QQ中实现,这里把QQ作为一个抽象基类,是为了告诉子类们:“请按接口设计重写方法”。

    关系梳理

    继承关系:
    在这里插入图片描述

    桥接模式:
    在这里插入图片描述

    能够看到,当平台与业务很多时,桥模式可以有效控制子类的增长速度。同时,注意桥接模式与装饰模式的区别。

    模式结构

    桥接模式包含如下角色:

    • Abstraction:抽象类
    • RefinedAbstraction:扩充抽象类
    • Implementor:实现类接口
    • ConcreteImplementor:具体实现类

    在这里插入图片描述

    总结

    桥接模式优点:

    • 分离抽象接口与实现部分,保证多维度下每个维度能够独立变化;
    • 桥接模式是对多继承方案的优化,提高代码复用性。

    桥接模式缺点:

    • 桥接模式要求正确识别出系统中两个独立变化的维度,因此其使用范围具有一定的局限性。

    感谢

    • 参考李建忠老师的《C++模式设计》
    • 参考《Graphic Design Patterns》中的桥接模式
    展开全文
  • 桥接模式示例

    2017-10-26 09:22:24
    清华大学设计模式教材,桥接模式课后习题,三维度桥接模式设计。
  • 设计模式专题之(十)桥接模式---设计模式桥接模式示例代码(python--c++)
  • 设计模式 - 桥接模式

    2017-07-18 10:36:49
    设计模式 - 桥接模式
  • 桥接模式Demo

    2017-06-09 13:46:45
    桥接模式Demo
  • JAVA设计模式--桥接模式

    万次阅读 2017-01-15 14:31:27
    一、什么是桥接模式 二、桥接模式的应用场景 三、桥接模式的结构 四、使用桥接模式重写消息示例 五、桥接模式的适用性 六、桥接模式的特点 七、总结 一、什么是桥接模式 桥接(Bridge)模式是构造型的设计模式...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 87,056
精华内容 34,822
关键字:

如何关闭桥接模式