title: "modern C++ DesignPattern-Part2"
date: 2018-04-10T19:08:49+08:00
lastmod: 2018-04-11T19:08:49+08:00
keywords: [设计模式, C++]
tags: [设计模式]
categories: []

Part2设计模式和结构化有较强的联系,分成两个part来解释,这篇主要包括桥接,适配器,装饰器这三种

Bridge

优点:

  • 通过这种模式可以将大量的没用到的成员与方法隐藏起来,只暴露出公用接口,降低复杂性
  • 可以通过前向声明 impl,把大量的include放到 impl.cpp里面,降低编译成本
struct Person{
std::string name;
class PersonImpl;
PersonImpl *impl; // bridge - not necessarily inner class, can vary
Person();
~Person();
void greet();
};
struct Person::PersonImpl
{
void greet(Person* p);
}; void Person::PersonImpl::greet(Person* p){
printf("hello %s", p->name.c_str());
}
Person::Person(): impl(new PersonImpl){}
Person::~Person(){ delete impl;}
void Person::greet(){ impl->greet(this);}

这个例子就是通过PersonImpl把大量的实现细节隐藏到了这个类里面,brpc中的server搭建就有很经典的使用. tips: Plmpl 编译防火墙 解除了接口与实现之间的耦合关系,从而降低文件间的编译依赖关系


Composite

这个模式比较简单,直接看代码,这是神经网络的neuron类例子

template <typename Self>
struct SomeNeurons { //主要是为了封装connect_to
template <typename T> void connect_to(T& other){
for (Neuron& from : *static_cast<Self*>(this)){
for (Neuron& to : other){
from.out.push_back(&to);
to.in.push_back(&from);
}
}
}
}; struct Neuron : SomeNeurons<Neuron>{
vector<Neuron*> in, out;
unsigned int id;
Neuron(){
static int id = 1; //static标记id,很方便
this->id = id++;
}
Neuron* begin() { return this; }
Neuron* end() { return this + 1; }
}; struct NeuronLayer : vector<Neuron>, SomeNeurons<NeuronLayer>{
NeuronLayer(int count){
while (count-- > 0)
emplace_back(Neuron{});
} //继承vector用来组合neuron向量,继承SomeNeurons用来解决连接问题
};

Decorator

C++11给这个模式带了了很多新东西,一起来看看吧

Dynamic Decorator

struct Shape{
virtual string str() const = 0;
};
struct ColoredShape : Shape{ //装饰类
Shape& shape;
string color;
ColoredShape(Shape& shape, const string& color): shape{shape}, color(color){}
string str() const override{...}
};
struct Circle: Shape {
float radius;
CirCle(float radius): radius(radius){}
resize(float factor) {radius *= factor};
string str() const override{...}
} Circle circle(0.6);
ColoredShape redCircle(circle, "red"); //shape引用

Static Decorator

前面动态类型的一个缺点是说被修饰的redCircle无法访问circle的方法, 比如 redCircle.resize(2) 编译不通过,下面这个实现方法就是为了解决这个问题的。这个方法的缺点是再编译期进行的装饰,没法重组合。

template <typename T>
struct ColoredShape: T{
static_assert(is_base_of<Shape,T>::value, "template arg must be a Shape");
string color;
ColoredShape(Shape& shape, string color): shape(shape), color(color){}
string str(){...}
}; ColoredShape<TransparentShape<Square>> square{"blue"}; //可以访问所有被修饰的层以及原本的square的所有成员
square.size = 2;
square.transparency = 0.5;
square.resize(3);

这里还有个缺点,通过这种方法,我们没法调用一次构造函数实现所有成员+修饰成员的初始化,解决方法为可变参数模板+类型推导

template <typename T>
struct TransparentShape: T{
int trans;
template<typename ...Args>
TransparentShape(const int trans, Args ...args):
T(std::forward<Args>(args)...), trans(trans){}
...
} ColoredShape2<TransparentShape2<Square>> sq = { "red", 51, 5 }; //这样初始化就没问题了

Functional Decorator

针对函数的装饰器

//1.不需要返回值
template <typename Func>
struct Logger2{
Func func;
string name;
Logger2(const Func& func, const string& name)
: func{func},
name{name}{}
void operator()() const{
cout << "Entering " << name << endl;
func();
cout << "Exiting " << name << endl;
}
}; template <typename Func>
auto make_logger2(Func func,
const string& name){
return Logger2<Func>{ func, name };
}
//call
auto call = make_logger2([](){cout<<"count"<<endl;}, "HelloFunc");
call();

还有一种是当有入参和返回值的需求时, 可变参数模板

template <typename> struct Logger3;  //为啥这里需要先部分特化的声明?
template <typename R, typename... Args>
struct Logger3<R(Args...)>
{
Logger3(function<R(Args...)> func, const string& name)
: func{func},
name{name}{}
R operator() (Args ...args){
cout << "Entering " << name << endl;
R result = func(args...);
cout << "Exiting " << name << endl;
return result;
} function<R(Args ...)> func;
string name;
}; template <typename R, typename... Args>
auto make_logger3(R (*func)(Args...), const string& name){
return Logger3<R(Args...)>(
std::function<R(Args...)>(func),
name);
} double add(double a, double b){
cout << a << "+" << b << "=" << (a + b) << endl;
return a + b;
} //call
auto logged_add = make_logger3(add, "Add");
auto result = logged_add(2, 3);

DesignPattern-part2的更多相关文章

  1. Linux平台 Oracle 10gR2(10.2.0.5)RAC安装 Part2:clusterware安装和升级

    Linux平台 Oracle 10gR2(10.2.0.5)RAC安装 Part2:clusterware安装和升级 环境:OEL 5.7 + Oracle 10.2.0.5 RAC 3.安装Clus ...

  2. Linux平台 Oracle 11gR2 RAC安装Part2:GI安装

    三.GI(Grid Infrastructure)安装 3.1 解压GI的安装包 3.2 安装配置Xmanager软件 3.3 共享存储LUN的赋权 3.4 使用Xmanager图形化界面安装GI 3 ...

  3. Hadoop入门学习笔记---part2

    在<Hadoop入门学习笔记---part1>中感觉自己虽然总结的比较详细,但是始终感觉有点凌乱.不够系统化,不够简洁.经过自己的推敲和总结,现在在此处概括性的总结一下,认为在准备搭建ha ...

  4. 小课堂week13 Clean Code Part2

    Clean Code Part2 对象与数据结构 首先让我们进行一个严肃的思考,对象与数据结构的区别在哪里? 如下两段代码分别用数据结构和对象的方法来描述了一个Point. public class ...

  5. K2 Blackpearl开发技术要点(Part2)

    转:http://www.cnblogs.com/dannyli/archive/2012/09/14/2685282.html K2 Blackpearl开发技术要点(Part2)  

  6. 小课堂Week9 例外处理设计的逆袭Part2

    小课堂Week9 例外处理设计的逆袭Part2 今天继续阅读<例外处理设计的逆袭>这本书,我们先看两个案例: 案例1 问:如果要设计一个依据学号到数据库中查询学生资料的函数,当找不到符合条 ...

  7. 《数字图像处理原理与实践(MATLAB版)》一书之代码Part2

    本文系<数字图像处理原理与实践(MATLAB版)>一书之代码系列的Part2(P43~80),代码运行结果请參见原书配图,建议下载代码前阅读下文: 关于<数字图像处理原理与实践(MA ...

  8. Linux平台 Oracle 12cR2 RAC安装Part2:GI配置

    Linux平台 Oracle 12cR2 RAC安装Part2:GI配置 三.GI(Grid Infrastructure)安装 3.1 解压GI的安装包 3.2 安装配置Xmanager软件 3.3 ...

  9. 自动化测试 Appium之Python运行环境搭建 Part2

    Appium之Python运行环境搭建 Part2 by:授客 QQ:1033553122 实践环境 参见 Appium之Python运行环境搭建 Part1 环境部署 1.安装Android SDK ...

  10. Linux平台 Oracle 18c RAC安装Part2:GI配置

    三.GI(Grid Infrastructure)安装 3.1 解压GI的安装包 3.2 安装配置Xmanager软件 3.3 共享存储LUN的赋权 3.4 使用Xmanager图形化界面配置GI 3 ...

随机推荐

  1. Uncaught TypeError: imageStyle.getImageState is not a function

    这个错误也是遇得到哟,柑橘自己好无辜呀,我哪里错了,找了半天原来还是自己找的错误 看 import Circle from 'ol/geom/Circle'; feature.setStyle(new ...

  2. fofa搜索技巧

    转载自:https://www.cnblogs.com/sunny11/p/14388508.html ` 目录 题记 技巧(我一般找国内的,所以下边一直加cn) 1.搜索HTTP响应头中含有&quo ...

  3. Python基础 - 标识符命名规范

    标识符是什么? 标识符主要用来给变量名,函数名,方法名,类名起名时要遵循的规范 硬性规则   见名知意(使用中文转译后的英文)  由字母,数字,下划线组成, 并且不能以数字开头, 不能和Python关 ...

  4. GroundingDINO(一种开集目标检测算法)服务化,根据文本生成检测框

    背景 最近发现一个叫GroundingDINO的开集目标检测算法,所谓开集目标检测就是能检测的目标类别不局限于训练的类别,这个算法可以通过输入文本的prompt然后输出对应的目标框.可以用来做预标注或 ...

  5. Not a managed type: class com.example.commonspojo.entity,公共实体类剥离,然后引入报错的问题及解决办法

    最近搞springcloud项目遇到在商品服务中调用基本服务时jvm扫描不到的问题 需要加@entityscan 学习博客: (9条消息) Not a managed type: class com. ...

  6. 基于 Dash Bio 的生物信息学数据可视化

    Dash 是用于搭建响应式 Web 应用的 Python 开源库.Dash Bio 是面向生物信息学,且与 Dash 兼容的组件,它可以将生物信息学领域中常见的数据整合到 Dash 应用程序,以实现响 ...

  7. PyInstaller 完美打包 Python 脚本,输出结构清晰、便于二次编辑的打包程序

    引入问题 如果我要写一个 Python 项目,打包成 exe 运行(方便在没有 Python 的电脑上使用),我需要打包出的根目录结构美观,没有多余的.杂乱的依赖文件在那里碍眼,而且需要在发现 bug ...

  8. 【后端面经】MySQL主键、唯一索引、联合索引的区别和作用

    目录 0. 简介 1. 主键 2. 唯一索引 3. 联合索引 4. 索引对数据库操作的影响 5. 其他索引 5.1 普通索引 5.2 全文索引 5.3 前缀索引 6. 总结 7. 参考资料 0. 简介 ...

  9. PHP文件包含总结

    1.文件包含小知识 1.1 包含函数 PHP共有4个与文件包含相关的函数: include require include_once require_once include与include_once ...

  10. 构建高可用性的 SQL Server:Docker 容器下的主从同步实现

    摘要:本文将介绍如何在 Docker 环境下搭建 MS SQL Server 的主从同步,帮助读者了解主从同步的原理和实现方式,进而提高数据的可靠性和稳定性. 一.前言 在当今信息化的时代,数据的安全 ...