做本地团购网站怎么样,绍兴注册公司,ui设计风格有哪几种,找网站建设公司文章目录 一、桥接模式二、std::error_code与设计模式#xff08;桥接模式#xff09;参考 一、桥接模式
在C中#xff0c;桥接模式通常涉及以下几个角色#xff1a;
抽象类接口#xff08;Abstraction#xff09;#xff1a;定义抽象部分的接口#xff0c;并维护一个… 文章目录 一、桥接模式二、std::error_code与设计模式桥接模式参考 一、桥接模式
在C中桥接模式通常涉及以下几个角色
抽象类接口Abstraction定义抽象部分的接口并维护一个指向实现部分的指针。具体抽象类ConcreteAbstraction继承自抽象类实现抽象部分的接口。实现类接口Implementor定义实现部分的接口。具体实现类ConcreteImplementor实现实现类接口并提供具体的实现。
以下是一些可能适合使用桥接模式的具体场景
图形界面工具包中的窗口和操作系统之间的连接使得可以在不同的操作系统上使用相同的窗口和控件。手机应用程序中的不同手机平台和不同功能的组合例如在不同的手机上实现相同的应用或者在同一手机上实现不同的应用。汽车制造业中汽车品牌和引擎类型之间的组合使得可以在不同的品牌车型上使用不同的引擎。电视机制造业中不同的电视品牌和不同的显示技术之间的组合使得可以在不同的品牌电视上使用不同的显示技术。
总之桥接模式适用于需要将抽象部分和实现部分分离的场景以实现灵活性、可扩展性和解耦的设计。它可以帮助处理多个维度上的变化并在运行时动态地切换抽象和实现的关系。
eg手机品牌和软件是两个概念不同的软件可以在不同的手机上不同的手机可以有相同的软件两者都具有很大的变动性。
如果我们单独以手机品牌或手机软件为基类来进行继承扩展的话无疑会使类的数目剧增并且耦合性很高如果更改品牌或增加软件都会增加很多的变动两种方式的结构如下
以将两者抽象出来两个基类分别是PhoneBrand和PhoneSoft那么在品牌类中聚合一个软件对象的基类将解决软件和手机扩展混乱的问题这样两者的扩展就相对灵活剪短了两者的必要联系结构图如下
// 实现类接口
class Implementor {
public:virtual void operationImpl() 0;
};// 具体实现类 A
class ConcreteImplementorA : public Implementor {
public:void operationImpl() override {// 具体实现 A// ...}
};// 具体实现类 B
class ConcreteImplementorB : public Implementor {
public:void operationImpl() override {// 具体实现 B// ...}
};// 抽象类
class Abstraction {
protected:Implementor* implementor;public:Abstraction(Implementor* impl) : implementor(impl) {}virtual void operation() 0;
};// 具体类 A
class ConcreteAbstractionA : public Abstraction {
public:ConcreteAbstractionA(Implementor* impl) : Abstraction(impl) {}void operation() override {// 具体类 A 的操作// ...implementor-operationImpl(); // 调用实现类接口// ...}
};// 具体类 B
class ConcreteAbstractionB : public Abstraction {
public:ConcreteAbstractionB(Implementor* impl) : Abstraction(impl) {}void operation() override {// 具体类 B 的操作// ...implementor-operationImpl(); // 调用实现类接口// ...}
};int main() {// 创建具体实现类对象Implementor* implA new ConcreteImplementorA();Implementor* implB new ConcreteImplementorB();// 创建具体类对象并传入具体实现类对象Abstraction* abstractionA new ConcreteAbstractionA(implA);Abstraction* abstractionB new ConcreteAbstractionB(implB);// 调用具体类的操作abstractionA-operation();abstractionB-operation();delete abstractionA;delete abstractionB;delete implA;delete implB;return 0;
}二、std::error_code与设计模式桥接模式
std::error_code 类图
标准库提供了创建std::error_code的方法参数传std::errc就行。
//std::error_code make_error_code( std::errc e ) noexcept;#include system_error
#include iostreamint main(){std::error_code ec std::make_error_code(std::errc::invalid_argument);std::coutec.message()\n;// 将输出Invalid argument
}稍微看一下std::make_error_code的实现
generic_category函数其实是一个全局函数返回的是std::error_category的单例。源码很简单通过构造std::error_code的函数可以看到std::error_code由两部分组成一部分是错误码的值一部分是std::error_category的单例。再回过头来看std::error_code类图就很清楚了。这里有个问题std::error_code的如果仅仅是通过std::make_error_code去创建而std::errc的错误码是有限的如果不够用的时候希望用一些专门领域的错误码该怎么办这个问题就是如何写自定义的错误码std::error_code其实已经考虑到这一点了它是可以扩展支持自定义错误码的。
inline error_code make_error_code(errc errno) noexcept {return error_code(static_castint(errno), std::generic_category());
}const std::error_category generic_category() noexcept;std::error_code的设计实际上是桥接模式它把抽象和实现分离了对于错误码来说抽象代表的是错误码的值实现代表的是具体的错误信息默认情况下std::errc表示错误码的值而std::error_category表示的是错误码对应的具体错误信息。
正是因为错误码的值会在不同的领域里含义不同所以才需要对它做抽象而具体的错误信息也是变化的不同领域里错误信息也不同所以这里非常适合用桥接模式来解耦和封装抽象和实现两部分的变化。
如果要实现自己的错误码只需要写自定义的错误码值和派生std::error_category去重写里面的错误信息相关的虚函数就行了。
eg雅兰亭库自定义错误码的实现
图中的单例也在这里是一个全局的函数里面有一个static instance成员:custom category
雅兰亭库里面struct_pack和struct_json都实现了自己的错误码也是根据std::error_code的桥接模式去实现的。以struct_pack的error_code为例
#include system_errornamespace struct_pack {
enum class errc {ok 0,no_buffer_space,invalid_argument,hash_conflict,
};namespace detail {class struct_pack_category : public std::error_category {public:virtual const char *name() const noexcept override {return struct_pack::category;}virtual std::string message(int err_val) const override {switch (static_casterrc(err_val)) {case errc::ok:return ok;case errc::no_buffer_space:return no buffer space;case errc::invalid_argument:return invalid argument;case errc::hash_conflict:return hash conflict;default:return (unrecognized error);}}
};inline const std::error_category category() {static struct_pack::detail::struct_pack_category instance;return instance;
}
} // namespace detail} // namespace struct_packinline std::error_code make_error_code(struct_pack::errc err) {return std::error_code(static_castint(err),struct_pack::detail::category());
}注意这里的make_error_code函数其实就是在抽象和实现中间建桥从而让std::error_code变成自定义的error_code一个关键点是实现了struct_pack_category而不是std::error_category它是自定义的派生于std::error_category所以输出的信息也是自定义的错误信息。
参考
C 桥接模式讲解和代码示例c 设计模式之桥接模式Bridge[Back to the basic] std::error_code与设计模式[Back to the basic] std::error_code与设计模式