企业网站的布局类型,百度推广怎么做免费,广州网站建设模板制作,网推什么意思C 设计模式 —— 桥接模式
0. 引用连接
本文主要的思路和代码#xff0c;来自于对以下连接的学习和实现#xff1a;
桥接模式
1. 引言
1.1 什么是桥接模式#xff1f;
桥接模式的定义桥接模式的作用
桥接模式#xff0c;顾名思义#xff0c;就像是一座连接两岸的桥…C 设计模式 —— 桥接模式
0. 引用连接
本文主要的思路和代码来自于对以下连接的学习和实现
桥接模式
1. 引言
1.1 什么是桥接模式
桥接模式的定义桥接模式的作用
桥接模式顾名思义就像是一座连接两岸的桥梁。在软件开发中我们可以将桥接模式看作是一座连接抽象部分和实现部分的“桥”通过这座“桥”我们可以方便地在抽象部分和实现部分之间进行切换而不需要关心它们之间的实现细节。
桥接模式的核心作用就是降低系统的耦合度提高扩展性和可维护性。想象一下你正在修建一座连接两个城市的大桥如果没有这座桥你需要绕行很远的距离才能到达对岸。同样地在软件开发中如果没有桥接模式抽象部分和实现部分之间的依赖关系可能会变得非常复杂导致系统难以扩展和维护。
1.2 桥接模式与其他设计模式的关系
桥接模式和其他设计模式的关系就像是一组不同的工具每个工具都有其独特的用途。就像在修建一座桥梁时我们可以选择使用各种不同的材料和工具来完成任务而不仅仅是一种。同样地在软件开发中我们可以结合使用不同的设计模式来解决不同的问题而桥接模式通常会于开发前期进行设计。桥接模式、状态模式和策略模式在某种程度上包括适配器都具有相似的接口它们都基于组合模式——即将工作委派给其他对象。但是它们各自解决了不同的问题。例如如果我们需要将一个类与它的子类进行关联并且希望在运行时动态地创建子类的实例那么桥接模式就非常适合。而如果我们需要对一个类的多个行为进行控制那么状态模式就是一个不错的选择。我们可以将抽象工厂模式和桥接搭配使用。如果由桥接定义的抽象只能与特定实现合作这一模式搭配就非常有用。在这种情况下抽象工厂可以对这些关系进行封装并且对客户端代码隐藏其复杂性。生成器模式和桥接模式也可以很好地结合使用主管类负责抽象工作各种不同的生成器负责实现工作。这就好比我们在修建桥梁时需要不同的工人来完成不同的任务一样生成器模式可以帮助我们更好地管理代码的生成过程。
桥接模式和其他设计模式都是非常有用的工具它们可以帮助我们更好地组织和管理代码提高系统的可维护性和可扩展性。在使用这些工具时我们需要根据具体的需求和场景来选择合适的模式以最大程度地发挥它们的效用。
1.3 桥接模式适用的场景
桥接模式的应用场景也非常广泛。比如我们正在开发一个电商网站其中有一个订单管理系统和一个支付系统。这两个系统分别负责订单的处理和支付的操作但是它们之间的关系非常紧密。如果没有桥接模式我们需要在订单管理系统和支付系统中都实现相同的逻辑这显然是不合理的。而如果我们使用桥接模式可以将订单管理系统和支付系统分别抽象成两个独立的类并通过一个桥接器来协调它们之间的交互这样就可以避免代码冗余和耦合度过高的问题。如果我们概括一下桥接模式的使用场景的话主要有以下几个
系统中存在多个独立但相互关联的类时可以使用桥接模式来解耦它们的依赖关系。当需要动态地创建一系列具有相似特性的对象时可以使用桥接模式来实现对象的创建和初始化过程。当需要在一个系统中灵活地切换不同的算法或策略时可以使用桥接模式来实现算法或策略的切换和组合。需要通过组合的方式在运行时对算法进行选择时可以使用桥接模式来避免使用多重条件语句。需要创建一个可以与多种类型接口进行交互的类时可以使用桥接模式来实现这个抽象。
2. 桥接模式的实现
桥接模式的实现方式就像是一座连接不同平台的桥梁它通过抽象部分和实现部分之间的关联来实现。如果以连接桥梁为例其大致的步骤为
需要明确类中独立的维度也就是确定抽象部分和实现部分之间的独立关系。这些独立的概念可以是抽象/平台、域/基础设施、前端/后端或接口/实现等。要了解客户端的业务需求并在抽象基类中定义它们。这就像在修建一座桥梁时我们需要考虑不同的交通需求比如车辆、行人等并设计出满足这些需求的桥梁结构。要确定在所有平台上都可执行的业务并在通用实现接口中声明抽象部分所需的业务。这就像是在选择材料和工具时我们需要选择那些能够适用于不同平台的通用材料和工具。可以为域内的所有平台创建实现类但需确保它们遵循实现部分的接口。这就像是在建造桥梁时我们需要根据设计图纸来建造每个平台的结构。在抽象类中添加指向实现类型的引用成员变量抽象部分会将大部分工作委派给该成员变量所指向的实现对象。这就像是在建造桥梁时将具体的施工任务委托给各个工人来完成。如果高层逻辑有多个变体则可通过扩展抽象基类为每个变体创建一个精确抽象。这就像是在不同的路段上修建不同类型的桥梁以满足不同的交通需求。
2.1 抽象部分
抽象部分在桥接模式中起到了至关重要的连接作用。它通过定义接口、封装逻辑、委派工作等方式将不同的平台进行连接并帮助客户端与实现部分进行交互。
抽象部分就像是一座桥梁的桥墩它具体负责了下面的一些内容
定义和封装与实现部分相关的接口和逻辑。需要承受来自不同平台的负荷并将这些负荷传递到实现部分。同样地抽象部分也需要承载客户端的业务需求并将这些需求传递给实现部分来完成具体的操作。定义一些通用的方法和属性这些方法和属性可以被多个实现类共享和使用。这就好比我们在建造一座桥梁时需要使用一些通用的材料和工具以便在不同的地方建造出相同的结构。通过添加引用成员变量来委派具体的实现对象。这样抽象部分就可以将大部分的工作交给具体实现来完成而自己只需要关注与客户端的交互即可。这就好比我们选择了一个优秀的工人来建造桥梁的一部分让他来完成整个工作而自己则专注于监督和管理。
2.2 具体部分
定义具体的子类这些子类实现了抽象部分定义的接口这些子类可以在运行时动态地被创建并通过抽象部分提供的接口与客户端代码进行交互
具体部分在桥接模式中同样起到了至关重要的作用。它通过实现抽象部分所定义的方法和属性完成具体的操作并帮助客户端与实现部分进行交互。同时具体部分还可以根据抽象部分的定义使用不同的实现方式来完成不同的业务逻辑。
具体部分就像是一座桥梁的桥面和支撑结构它具体负责了下面的一些内容
实现抽象部分定义的接口和逻辑。承载客户端的业务需求并将这些需求实现成具体的操作。通过添加额外的实现类来实现不同的业务逻辑。这就好比我们在建造一座桥梁时需要使用不同的材料和工具来建造出不同的结构。具体部分也需要根据抽象部分的定义使用不同的实现方式来完成不同的业务逻辑。通过扩展抽象基类为每个变体创建一个精确抽象。这样我们就可以针对不同的平台创建不同的具体实现以满足不同的业务需求。这就好比我们在不同的路段上修建不同类型的桥梁以满足不同的交通需求。
3. 桥接模式的优点和缺点
3.1 优点
允许我们创建与平台无关的类和程序。这意味着我们可以将不同的平台抽象出来形成一个统一的高层接口。这样无论我们在哪个平台上进行开发都可以使用相同的类和接口来进行交互而不需要关心具体的平台细节。客户端代码仅与高层抽象部分进行互动不会接触到平台的详细信息。这就好比我们通过一座桥梁来连接两个不同的地点我们只需要关注桥梁上的路径和交通情况而不需要了解每个地点的具体信息。桥接模式还遵循了开闭原则。我们可以新增抽象部分和实现部分并且它们之间不会相互影响。这就好比我们可以通过添加新的桥梁来连接更多的地点而不需要修改已有的桥梁结构。这种灵活性使得我们的系统可以更容易地适应新的需求和变化。桥接模式也符合单一职责原则。抽象部分专注于处理高层逻辑实现部分处理平台细节。这就好比一个桥梁的设计者只需要负责设计出合适的桥梁结构和路径规划而不需要关心具体的材料和施工细节。这种分离使得各个部分的职责更加明确易于维护和扩展。
综上所述桥接模式的优点在于它可以帮助我们更好地组织和管理代码提高系统的可维护性和可扩展性。通过创建与平台无关的类和程序、客户端代码仅与高层抽象部分进行互动、遵循开闭原则以及单一职责原则等特性桥接模式为我们提供了一个灵活、高效且易于维护的设计方案。
3.2 缺点
对于高内聚的类来说使用桥接模式可能会让代码变得更加复杂。这是因为在桥接模式中我们需要将抽象部分和实现部分分离开来这可能会增加代码的复杂度。就像建造一座复杂的桥梁需要更多的设计和施工工作一样使用桥接模式也需要更多的思考和编码工作。使用桥接模式可能会导致抽象部分的代码量增加从而影响系统的性能。这是因为抽象部分需要承担更多的职责和功能可能需要处理更多的细节和逻辑。就像一座桥梁上的支撑结构需要承受更大的负荷一样抽象部分也需要处理更多的业务逻辑和操作。使用桥接模式可能会增加系统的复杂性使得理解和修改代码变得更加困难。这是因为桥接模式将抽象部分和实现部分分离开来可能会增加代码的耦合度和依赖关系。就像建造一座复杂的桥梁需要更多的协调和管理一样使用桥接模式也需要更多的关注和维护。客户端代码不正确地使用了抽象部分提供的接口可能会导致系统出现错误或异常行为。这是因为抽象部分需要负责定义和封装接口如果客户端代码没有正确地调用这些接口就会导致系统的错误和异常。就像使用错误的桥梁路径会导致交通拥堵一样客户端代码的错误使用也会给系统带来问题。
综上所述桥接模式是一种灵活的设计模式可以帮助我们更好地组织和管理代码。然而在使用该模式时也需要注意一些潜在的问题和挑战。就像建造一座桥梁需要考虑许多因素一样使用桥接模式也需要综合考虑各种因素以确保系统的正确性和可靠性。
4. 代码实现
4.1 真实案例伪代码描述
// “抽象部分”定义了两个类层次结构中“控制”部分的接口。它管理着一个指向“实
// 现部分”层次结构中对象的引用并会将所有真实工作委派给该对象。
class RemoteControl isprotected field device: Deviceconstructor RemoteControl(device: Device) isthis.device devicemethod togglePower() isif (device.isEnabled()) thendevice.disable()elsedevice.enable()method volumeDown() isdevice.setVolume(device.getVolume() - 10)method volumeUp() isdevice.setVolume(device.getVolume() 10)method channelDown() isdevice.setChannel(device.getChannel() - 1)method channelUp() isdevice.setChannel(device.getChannel() 1)// 你可以独立于设备类的方式从抽象层中扩展类。
class AdvancedRemoteControl extends RemoteControl ismethod mute() isdevice.setVolume(0)// “实现部分”接口声明了在所有具体实现类中通用的方法。它不需要与抽象接口相
// 匹配。实际上这两个接口可以完全不一样。通常实现接口只提供原语操作而
// 抽象接口则会基于这些操作定义较高层次的操作。
interface Device ismethod isEnabled()method enable()method disable()method getVolume()method setVolume(percent)method getChannel()method setChannel(channel)// 所有设备都遵循相同的接口。
class Tv implements Device is// ……class Radio implements Device is// ……// 客户端代码中的某个位置。
tv new Tv()
remote new RemoteControl(tv)
remote.togglePower()radio new Radio()
remote new AdvancedRemoteControl(radio)4.2 概念示例代码
#include iostream
#include string/*** The Implementation defines the interface for all implementation classes. It* doesnt have to match the Abstractions interface. In fact, the two* interfaces can be entirely different. Typically the Implementation interface* provides only primitive operations, while the Abstraction defines higher-* level operations based on those primitives.*/
class Implementation
{
public:virtual ~Implementation() {}virtual std::string OperationImplementation() const 0;
};/*** Each Concrete Implementation corresponds to a specific platform and* implements the Implementation interface using that platforms API.*/
class ConcreteImplementationA : public Implementation
{
public:std::string OperationImplementation() const override{return ConcreteImplementationA: Heres the result on the platform A.\n;}
};
class ConcreteImplementationB : public Implementation
{
public:std::string OperationImplementation() const override{return ConcreteImplementationB: Heres the result on the platform B.\n;}
};/*** The Abstraction defines the interface for the control part of the two class* hierarchies. It maintains a reference to an object of the Implementation* hierarchy and delegates all of the real work to this object.*/
class Abstraction
{/*** var Implementation*/
protected:Implementation *implementation_;public:Abstraction(Implementation *implementation) : implementation_(implementation){}virtual ~Abstraction(){}virtual std::string Operation() const{return Abstraction: Base operation with:\n this-implementation_-OperationImplementation();}
};/*** You can extend the Abstraction without changing the Implementation classes.*/
class ExtendedAbstraction : public Abstraction
{
public:ExtendedAbstraction(Implementation *implementation) : Abstraction(implementation){}std::string Operation() const override{return ExtendedAbstraction: Extended operation with:\n this-implementation_-OperationImplementation();}
};/*** Except for the initialization phase, where an Abstraction object gets linked* with a specific Implementation object, the client code should only depend on* the Abstraction class. This way the client code can support any abstraction-* implementation combination.*/
void ClientCode(const Abstraction abstraction)
{// ...std::cout abstraction.Operation();// ...
}/*** The client code should be able to work with any pre-configured abstraction-* implementation combination.*/
void BridgeExample()
{Implementation *implementation new ConcreteImplementationA;Abstraction *abstraction new Abstraction(implementation);ClientCode(*abstraction);std::cout std::endl;delete implementation;delete abstraction;implementation new ConcreteImplementationB;abstraction new ExtendedAbstraction(implementation);ClientCode(*abstraction);delete implementation;delete abstraction;
}4.3 真实案例代码
4.3.1 remote_exmaple.h
#ifndef _REMOTE_EXAMPLE_H_
#define _REMOTE_EXAMPLE_H_// The abstract Device class.
class Device
{
public:virtual bool isEnabled() 0;virtual void enable() 0;virtual void disable() 0;virtual int getVolume() 0;virtual void setVolume(int volume) 0;virtual int getChannel() 0;virtual void setChannel(int channel) 0;protected:virtual bool checkIsValidVolume(int volume) const 0;virtual bool checkIsValidChannel(int channel) const 0;
};class RemoteControl
{
protected:Device* m_pDevice nullptr;
public:RemoteControl(Device* pDevice);void togglePower();void volumeDown();void volumeUp();void channelDown();void channelUp();
};class AdvancedRemoteControl : public RemoteControl
{
public:void mute();
};class TVDevice : public Device
{
public:TVDevice(bool isEnabled false, int volume 1, int channel 0);bool isEnabled() override;void enable() override;void disable() override;int getVolume() override;void setVolume(int volume) override;int getChannel() override;void setChannel(int channel) override;void printDeviceInfo();private:bool checkIsValidVolume(int volume) const override;bool checkIsValidChannel(int channel) const override;private:bool m_isEnabled false;int m_volume 1;int m_channel 0;
};class RadioDevice : public Device
{
public:RadioDevice(bool isEnabled false, int volume 1, int channel 0);bool isEnabled() override;void enable() override;void disable() override;int getVolume() override;void setVolume(int volume) override;int getChannel() override;void setChannel(int channel) override;void printDeviceInfo();private:bool checkIsValidVolume(int volume) const override;bool checkIsValidChannel(int channel) const override;private:bool m_isEnabled false;int m_volume 1;int m_channel 0;
};class RemoteExample
{
public:static void TVControlCase();static void RadioControlCase();
};#endif // _REMOTE_EXAMPLE_H_
4.3.2 remote_example.cpp
#include remote_example.h#include iostreamnamespace
{constexpr int TV_VOLUME_MAX 100;constexpr int TV_CHANNEL_MAX 256;constexpr int RADIO_VOLUME_MAX 200;constexpr int RADIO_CHANNEL_MAX 512;
}RemoteControl::RemoteControl(Device* pDevice): m_pDevice(pDevice)
{
}void RemoteControl::togglePower()
{if (m_pDevice-isEnabled()) {m_pDevice-disable();} else {m_pDevice-enable();}
}void RemoteControl::volumeDown()
{m_pDevice-setVolume(m_pDevice-getVolume() - 10);
}void RemoteControl::volumeUp()
{m_pDevice-setVolume(m_pDevice-getVolume() 10);
}void RemoteControl::channelDown()
{m_pDevice-setChannel(m_pDevice-getChannel() - 1);
}void RemoteControl::channelUp()
{m_pDevice-setChannel(m_pDevice-getChannel() 1);
}void AdvancedRemoteControl::mute()
{m_pDevice-setVolume(0);
}TVDevice::TVDevice(bool isEnabled /* true*/, int volume /* 1*/, int channel /* 0*/): m_isEnabled(isEnabled), m_volume(volume), m_channel(channel)
{
}bool TVDevice::isEnabled()
{return m_isEnabled;
}void TVDevice::enable()
{m_isEnabled true;
}void TVDevice::disable()
{m_isEnabled false;
}int TVDevice::getVolume()
{return m_volume;
}void TVDevice::setVolume(int volume)
{if (checkIsValidVolume(volume)){m_volume volume;}else{std::cout Error volume for this TV Device! std::endl;}
}int TVDevice::getChannel()
{return m_channel;
}void TVDevice::setChannel(int channel)
{if (checkIsValidChannel(channel)){m_channel channel;}else{std::cout Error channel for this TV Device! std::endl;}
}void TVDevice::printDeviceInfo()
{std::cout TVDevice Info : Volume : m_volume \t Channel : m_channel std::endl;
}bool TVDevice::checkIsValidVolume(int volume) const
{return (volume 0 volume TV_VOLUME_MAX) ? true : false;
}bool TVDevice::checkIsValidChannel(int channel) const
{return (channel 0 channel TV_CHANNEL_MAX) ? true : false;
}RadioDevice::RadioDevice(bool isEnabled /* true*/, int volume /* 1*/, int channel /* 0*/): m_isEnabled(isEnabled), m_volume(volume), m_channel(channel)
{
}bool RadioDevice::isEnabled()
{return m_isEnabled;
}void RadioDevice::enable()
{m_isEnabled true;
}void RadioDevice::disable()
{m_isEnabled false;
}int RadioDevice::getVolume()
{return m_volume;
}void RadioDevice::setVolume(int volume)
{if (checkIsValidVolume(volume)){m_volume volume;}else{std::cout Error volume for this TV Device! std::endl;}
}int RadioDevice::getChannel()
{return m_channel;
}void RadioDevice::setChannel(int channel)
{if (checkIsValidChannel(channel)){m_channel channel;}else{std::cout Error channel for this TV Device! std::endl;}
}bool RadioDevice::checkIsValidVolume(int volume) const
{return (volume 0 volume RADIO_VOLUME_MAX) ? true : false;
}bool RadioDevice::checkIsValidChannel(int channel) const
{return (channel 0 channel RADIO_CHANNEL_MAX) ? true : false;
}void RadioDevice::printDeviceInfo()
{std::cout RadioDevice Info : Volume : m_volume \t Channel : m_channel std::endl;
}void RemoteExample::TVControlCase()
{std::cout \nTV Device example case start. std::endl;TVDevice tv;RemoteControl remoteTv(tv);remoteTv.togglePower();tv.printDeviceInfo();remoteTv.channelUp();std::cout After TV channel up: std::endl;tv.printDeviceInfo();remoteTv.volumeUp();std::cout After TV volume Up: std::endl;tv.printDeviceInfo();AdvancedRemoteControl adRemote(tv);adRemote.mute();std::cout After TV is muted: std::endl;tv.printDeviceInfo();std::cout \nTV Device example case end. std::endl;
}void RemoteExample::RadioControlCase()
{std::cout \nRadio Device example case start. std::endl;RadioDevice radio;RemoteControl remoteRadio(radio);remoteRadio.togglePower();radio.printDeviceInfo();remoteRadio.channelUp();std::cout After Radio channel up: std::endl;radio.printDeviceInfo();remoteRadio.volumeUp();std::cout After Radio volume Up: std::endl;radio.printDeviceInfo();AdvancedRemoteControl adRemote(radio);adRemote.mute();std::cout After Radio is muted: std::endl;radio.printDeviceInfo();std::cout \nRadio Device example case end. std::endl;
}4.4 代码分析
4.4.1 概念代码分析
相关代码由以下类组成 Implementation这是一个抽象基类定义了所有实现类的接口。它有一个纯虚函数 OperationImplementation()。 ConcreteImplementationA 和 ConcreteImplementationB这两个类是 Implementation 的具体实现分别对应平台A和平台B。它们实现了 OperationImplementation() 方法返回特定平台的结果。 Abstraction这个类定义了控制部分的接口并维护了一个对 Implementation 类的对象的引用。它有一个虚函数 Operation()该函数通过委托给 implementation_ 对象来执行实际工作。 ExtendedAbstraction这是 Abstraction 的子类扩展了其功能。它在 Operation() 中添加了一些额外的操作。 ClientCode 和 BridgeExample这两个函数/方法用于客户端代码与抽象和实现类进行交互。
这些类的角色如下
Implementation定义了所有实现类的接口。ConcreteImplementationA 和 ConcreteImplementationB实现了 Implementation 接口提供了特定平台的实现。Abstraction作为控制部分的接口封装了对 Implementation 对象的引用并提供了基本的操作。ExtendedAbstraction扩展了 Abstraction 的功能。ClientCode 和 BridgeExample客户端代码与抽象和实现类进行交互。
模式中的各个元素以以下方式相互关联
Abstraction 类包含一个指向 Implementation 类的指针并通过该指针调用 OperationImplementation() 方法。ExtendedAbstraction 类继承自 Abstraction 类并重写了 Operation() 方法增加了额外的操作。ClientCode 函数接受一个 Abstraction 类的引用并通过该引用调用 Operation() 方法。BridgeExample 函数演示了如何使用不同的 Abstraction 和 Implementation 组合创建对象并通过 ClientCode 函数调用相应的操作。
4.4.2 真实案例代码分析
相关代码由以下类组成 Device这是一个抽象类定义了一些设备共有的属性和方法如检查设备是否启用、获取和设置音量和频道等。 RemoteControl这是一个基类它有一个指向Device类的指针并定义了一些远程控制设备的基本操作如切换电源、调整音量和频道等。 AdvancedRemoteControl这是RemoteControl的子类增加了静音功能。 TVDevice 和 RadioDevice这两个类都继承自Device类分别代表电视设备和无线电设备。它们都实现了Device类中的虚函数并添加了一些特定于设备的属性和方法如打印设备信息等。 RemoteExample这是一个包含两个静态方法的类用于在其他地方调用以执行特定的远程控制案例。
这些类的角色如下
Device作为所有设备的基类定义了通用的设备属性和方法。RemoteControl作为远程控制的基类提供了一些设备的基本操作。AdvancedRemoteControl扩展了远程控制的功能包括静音。TVDevice 和 RadioDevice这两个类代表了具体的设备类型它们继承了Device类并实现了Device类中的方法添加了特定于设备的属性和方法。RemoteExample包含了两个静态方法用于在其他地方执行特定的远程控制案例。