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. AIGC持续火爆大模型争相推出,庞大市场造就算力供应模式演变

    本图由AI生成 黄仁勋说的AI发展迎来iPhone时刻,对NVIDIA有什么影响? 文/王吉伟 近期的AIGC领域仍旧火爆异常. 但火的不只是AIGC应用,还有巨头之间的AI竞赛,以及接连不断上新的A ...

  2. weex项目使用iconfont 字体图标

    一.使用本地字体图标 1.在 https://www.iconfont.cn/manage/index 注册自己的账号 2.创建自己的项目 3.添加自己需要的图标,并将其下载到本地 4.入口页面引入 ...

  3. Cobalt Strike 连接启动教程(1)

      第一步:把cobaltstrike4(解压后)拷贝到虚拟机Kali系统的root目录下 第二步:进入cobalstrike4文件夹中 第三步:选寻kali系统 IP地址 第四步: 启动服务端:(t ...

  4. shader编程经典:分形--科赫曲线

    序言 科赫(雪花)曲线是一个经典分形图案,来一起领略下分形之美.本篇内容用到一些基础的内容,例如UV的理解和画线技巧,有需要的话可以参考合集的画圆和画线两篇文章. 示例 shadertoy 代码: # ...

  5. 远程desk工具利用总结

    NO.1 Todesk 根据目标软件安装情况有以下两种利用方法 1.目标机已有完整版todesk. 1)改配置文件. 老版本可替换至本地查看密码(此法在最近更新的几个版本中已经失效),新版本只可更改密 ...

  6. 00.Webstrom的基本入门设置

    1.取消红框类自动打开项目 2.打开轮滚缩放代码 3.设置代码字体,这里选择的是Consolas 推荐免费字体:https://files.cnblogs.com/files/huadaxia/jet ...

  7. 【C#/.NET】record介绍

    ​  目录 什么是record? 使用record record解构 record原理 结论 什么是record? record是.NET 5中的一种新特性,可以看作是一种概念上不可变的类.recor ...

  8. 2023-06-16:给你一份工作时间表 hours,上面记录着某一位员工每天的工作小时数。 我们认为当员工一天中的工作小时数大于 8 小时的时候,那么这一天就是「劳累的一天」。 所谓「表现良好的时间

    2023-06-16:给你一份工作时间表 hours,上面记录着某一位员工每天的工作小时数. 我们认为当员工一天中的工作小时数大于 8 小时的时候,那么这一天就是「劳累的一天」. 所谓「表现良好的时间 ...

  9. springboot中自定义JavaBean返回的json对象属性名称大写变小写问题

    目录 一.继承类 二.手动添加Get方法 三.@JsonProperty 四.spring-boot json(jackson)属性命名策略 开发过程中发现查询返回的数据出现自定义的JavaBean的 ...

  10. String解析及其方法

    String解析及其方法 1.前言 2.什么是字符串(String) 3.字符串(String)的两种创建方式及其区别 4.字符串(String)的方法及其部分原码解析 5.字符串(String)的弊 ...