首页 > 其他分享 >DesignPattern-part2

DesignPattern-part2

时间:2023-03-24 19:33:59浏览次数:50  
标签:const struct Person name DesignPattern part2 func string

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);

标签:const,struct,Person,name,DesignPattern,part2,func,string
From: https://www.cnblogs.com/sunstrikes/p/17253110.html

相关文章

  • DesignPatternPrinciple-设计模式原则
    1.单一职责原则(SingleResponsibilityPrinciple)类T负责两个不同的职责:职责P1,职责P2。usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSys......
  • rtk 快速实践 创建一个Post part2 文章列表和添加新文章
    这一节大概能对应文档的数据流结构项目启动大家好,经过rtk快速上手和前个视频的开发环境搭建,下面我们开始真正动手实践吖。从文档的探索初始项目开始,但是稍微有区别,以......
  • 第七章 类Part2
    深拷贝和浅拷贝浅拷贝同一类型的对象之间可以赋值,使得两个对象的成员变量的值相同,两个对象仍然是独立的两个对象,这种情况被称为浅拷贝.一般情况下,浅拷贝没有任何副作用......
  • 2.大并发服务器架构Part2
    ......
  • Part2
    类成员指针classTest{public: voidoutput() { cout<<"outputnotstatic"<<endl; } staticvoidstaoutput()//本质属于类 { cout<<"staticfunct......
  • part2_01神经网络的准备
    神经网络的概念由连接主义学派提出。每一个神经网络都由若干个互有交互、连接的感知器,或称为神经元,以网络连接层的形式构成,感知器与感知器之间在满足特定的条件下会互相传......
  • PART2 离散傅里叶变换
    PART2离散傅里叶变换1.离散时间傅里叶变换以上内容,属于对傅里叶变换较为基础的数学内容,在《微积分》等课程中有不少详尽的介绍。接下来,将会面对如何在计算机中实现傅......
  • Qt做大型软件开发技术选型Part2:Qt调用C#编写的COM组件
    Qt做大型软件开发技术选型Part2:Qt调用C#编写的COM组件之前有提到过我们项目部现在正在用Qt重构一个大型软件,现在的情景是这样的:原先的软件是通过一个C++(CLR)的主程序,调......
  • part2_03Sklearn数据预处理
    6非结构性数据预处理非结构化数据是数据结构不规则或者说是不完整,没有预设的数据模型或者结构,不便使用数据库、模型及标准的数据接口表现的数据,包括所有格式的文本、图片......
  • 逆向路由器固件之敏感信息泄露 Part2——物联网安全——信息收集,获取db中的用户名和密
    逆向路由器固件之敏感信息泄露Part2 之前的文章中详细介绍了各种解包路由器固件的工具。解包之后就获得了固件中的文件。下一步就是分析文件寻找漏洞了。这次......