zoukankan      html  css  js  c++  java
  • 【设计模式

    一、定义

    考虑这样一个需求:绘制矩形、圆形、三角形这三种图案。按照面向对象的理念,我们至少需要个具体类,对应三种不同的图形。

    // 抽象形状类IShape
    class IShape {
    public:
        void draw();
    };
    
    // 三个具体形状类:矩形、圆形、三角形
    class Rectangle: public IShape {
    public:
        void draw() {
            cout << "绘制矩形" << endl;
        }
    };
    class Round: public IShape {
    public:
        void draw() {
            cout << "绘制圆形" << endl;
        }
    };
    class Triangle: public IShape {
    public:
        void draw() {
            cout << "绘制三角形" << endl;
        }
    };
    

    接下来我们有了新的需求,每种形状都需要有四种不同的颜色:红、蓝、黄、绿。

    这时我们很容易想到两种设计方案:

    • 为了复用形状类,将每种形状定义为父类,每种不同颜色的图形继承自其形状父类。此时一共有 12 个类。
    • 为了复用颜色类,将每种颜色定义为父类,每种不同颜色的图形继承自其颜色父类。此时一共有 12 个类。

    乍一看没什么问题,我们使用了面向对象的继承特性,复用了父类的代码并扩展了新的功能。

    但仔细想想,如果以后要増加一种颜色,比如黑色,那么我们就需要增加三个类;如果再要增加一种形状,我们又需要增加五个类,对应 5 种颜色。更不用说遇到增加 20 个形状,20 种颜色的需求,不同的排列组合将会使工作量变得无比的庞大。看来我们不得不重新思考设计方案。

    形状和颜色,都是图形的两个属性。他们两者的关系是平等的,所以不属于继承关系。更好的的实现方式是:将形状和颜色分离,根据需要对形状和颜色进行组合,这就是桥接模式的思想。

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

    官方定义非常精准、简练,但却有点不易理解。通俗地说,如果一个对象有两种或者多种分类方式,并且两种分类方式都容易变化,比如本例中的形状和颜色。这时使用继承很容易造成子类越来越多,所以更好的做法是把这种分类方式分离出来,让他们独立变化,使用时将不同的分类进行组合即可。


    二、结构

    桥接(Bridge)模式包含以下主要角色。

    • 抽象化(Abstraction)角色:定义抽象类,并包含一个对实现化对象的引用。
    • 扩展抽象化(Refined Abstraction)角色:是抽象化角色的子类,实现父类中的业务方法,并通过组合关系调用实现化角色中的业务方法。
    • 实现化(Implementor)角色:定义实现化角色的接口,供扩展抽象化角色调用。
    • 具体实现化(Concrete Implementor)角色:给出实现化角色接口的具体实现。

    其结构图如下图所示:
    桥接模式的结构图


    二、程序实现

    实现程序如下:

    #include <iostream>
    #include <string>
    
    using namespace std;
    
    // 实现化角色: 颜色类IColor
    class IColor {
    public:
        virtual string getColor() = 0;
    };
    
    // 具体实现化角色A
    class Red: public IColor {
    public:
        string getColor() {
            return "红";
        }
    };
    
    // 具体实现化角色B
    class Blue: public IColor {
    public:
        string getColor() {
            return "蓝";
        }
    };
    
    // 具体实现化角色C
    class Yellow: public IColor {
    public:
        string getColor() {
            return "黄";
        }
    };
    
    // 具体实现化角色D
    class Green: public IColor {
    public:
        string getColor() {
            return "绿";
        }
    };
    
    // 抽象化角色: 形状类IShape
    class IShape {
    public:
        virtual void setColor(IColor *color) = 0;
        virtual void draw() = 0;
    };
    
    // 扩展抽象化角色A
    class Rectangle: public IShape {
    public:
        void setColor(IColor *color) {
            this->m_color = color;
        }
    
        void draw() {
            cout << "绘制" << m_color->getColor() << "矩形" << endl;
        }
    
    private:
        IColor *m_color;
    };
    
    // 扩展抽象化角色B
    class Round: public IShape {
    public:
        void setColor(IColor *color) {
            this->m_color = color;
        }
    
        void draw() {
            cout << "绘制" << m_color->getColor() << "圆形" << endl;
        }
    
    private:
        IColor *m_color;
    };
    
    // 扩展抽象化角色C
    class Triangle: public IShape {
    public:
        void setColor(IColor *color) {
            this->m_color = color;
        }
    
        void draw() {
            cout << "绘制" << m_color->getColor() << "三角形" << endl;
        }
    
    private:
        IColor *m_color;
    };
    
    int main()
    {
        Rectangle *rectangle = new Rectangle();
        rectangle->setColor(new Red());
        rectangle->draw();
    
        Round *round = new Round();
        round->setColor(new Blue());
        round->draw();
    
        Triangle *triangle = new Triangle();
        triangle->setColor(new Yellow());
        triangle->draw();
    
        return 0;
    }
    

    输出如下:

    绘制红矩形
    绘制蓝圆形
    绘制黄三角形
    

    这时我们再来回顾一下官方定义:将抽象部分与它的实现部分分离,使它们都可以独立地变化。抽象部分指的是父类,对应本例中的形状类,实现部分指的是不同子类的区别之处。将子类的区别方式——也就是本例中的颜色——分离成接口,通过组合的方式桥接颜色和形状,这就是桥接模式,它主要用于两个或多个同等级的接口。


    参考:

    知乎 - 如何学习设计模式? 热门回答

    菜鸟教程 - 设计模式篇

    桥接模式(Bridge模式)详解


  • 相关阅读:
    服务注册发现Eureka之二:高可用服务注册中心
    可重入锁 公平锁 读写锁、CLH队列、CLH队列锁、自旋锁、排队自旋锁、MCS锁、CLH锁
    红黑树(Red-Black tree)
    fuser 命令小结
    客户端负载均衡Ribbon之三:AvailabilityFilteringRule的坑(Spring Cloud Finchley.SR2)
    mysql重复记录的查询删除方法
    innodb的锁、update单条记录的花费时间压测
    被kill问题之1:进程物理内存远大于Xmx的问题分析
    服务注册发现Eureka之三:Spring Cloud Ribbon实现客户端负载均衡(客户端负载均衡Ribbon之三:使用Ribbon实现客户端的均衡负载)
    十二、jdk工具之jcmd介绍(堆转储、堆分析、获取系统信息、查看堆外内存)
  • 原文地址:https://www.cnblogs.com/linuxAndMcu/p/13678929.html
Copyright © 2011-2022 走看看