随便写写,用于记录,工厂方法

对象设计模式

工厂方法

例如在在一个类A中, 例如我需要在运行的过程中创建令一个类的对象。但是如果直接NEW对象 B,那么这个B就和这个A产生了强依赖,A在编译的时候就依赖B了
例如如下代码:

#include <iostream>

#include <map>

class splitter{
public:
  virtual void split() = 0;课程
};

class TxtSplitter : public splitter{
  void split() override{
    std::cout << " 1" << std::endl;
  }
};

class MusicSplitter : public splitter{
  void split() override{
    std::cout << "2" << std::endl;
  }
};

class Button {
public:
  Button(){
  }

  void click(){
    splitter* spl = new MusicSplitter();
    spl ->split();
    delete(spl);
  }

private:
};

int main() {
  auto button =  Button();
  button.click();
}

例如我有一个类Button, 在用户点击按钮之后会调用click方法,之后这个函数需要将用户选择的内容分解为数个部分。用户选择的内容可能是音乐,文件等。 所以很容易想到将 split抽象出一个方法, 例如上述代码中的 class splitter 。 TxtSplitter 和 MusicSplitter分别实现文件分割和音乐的分割。之后在 class Button 在是实例化相应的对象, 这样子看似可以,但实际上 Button 和 MusicSplitter 产生了强依赖。在编的编译的时候编译TxtSplitter 必须 需要MusicSplitter。

如何改进呢? 看下列的代码


class ISplitterFactory{
public:
  virtual ISplitter* CreateSplitterFactory() = 0;
};


class TxtSplitterFactory : public ISplitterFactory{
public:
  ISplitter* CreateSplitterFactory() override{
    return  new MusicSplitter();
  }
};

用一个抽象类将里面放一个方法用于去生成ISplitter对象。
之后的buottn的代码可以写成下面的样子:

class Button1 {ISplitterFactory
public:
  Button1(ISplitterFactory *sql_factory)
  : SqlFactory_(sql_factory)
  {
  }

  void click(){
  	//千万不可以写成这样子,如果写成这样子实际上又和上面一样了。
  	//ISplitter* spl = TxtSplitterFactory().CreateSplitterFactory();
    ISplitter* spl = SqlFactory_->CreateSplitterFactory();
    spl ->split();
    delete(spl);
  }

private:
  ISplitterFactory* SqlFactory_;
};

这样子,虽然最终编译的时候为们还是需要TxtSplitterFactory,但Button1实际上和前者已经没有强依赖了。
外部的函数可以写成这样子

int main() {
//  auto button =  Button();
//  button.click();
  TxtSplitterFactory* factory =  new TxtSplitterFactory(); //通过这个方法就可以将初始化的时间延续到运行时;
  Button1 a(factory);
  a.click();
}

上面的情况比较简单,只有一个步骤,但如果是一个很复杂的过程,例如:数据库的操作, 连接, 读取,解析一系列步骤,而每个步骤都需要一个新的对象。 那么就相当于每一个对象都需要一个工厂了,上面的三个步骤就相当于三个对象。 例如:


class SqlConnection : public IDbConnection{
public:
  void connection() override{
    std::cout << "connection" << std::endl;
  }
};

class SqlCommand : public IDbCommand{
  void execute() override{
    std::cout << "execute" << std::endl;
  }
};

class SqlReader : public IDataReader{
  void reader() override{
    std::cout << "read" << std::endl;
  }
};

加入要支持 influxdb 那么就需要在写三个。
但是这样有一个问题SqlConnection对象的结果只能用SqlCommand处理。 而不能用influxdbCommand。 这样子我们可以写的更好一点

class IDBFactory{
public:
  virtual IDbConnection* CreateDbConnection() =0;
  virtual IDbCommand* CreateDbCommand() = 0;
  virtual IDataReader* CreateDbReader() = 0;
};


class EmployDao{
  IDBFactory* dbFactory;
public:
  std::vector<std::string> GetEmploy(){
    IDbConnection* connection = dbFactory->CreateDbConnection();
    //...
    IDbCommand* cmd = dbFactory->CreateDbCommand();
    //...
    IDataReader* reader = dbFactory->CreateDbReader();
  }
};

一个这样的工厂,这样子就将同一类的封装起来了。 通过一个工厂生成多个不同的对象。

proptype 原型对象

如果一个类有很多中间状态,创建之后如果要经过一两个阶段之后才可以使用,那么对于这样的类可以使用原型模式, 通过clone的方法直接将这个对象拷贝出来
例如:

class MainForm {
private:
  ISplitter1* prototype_;
public:
  MainForm(ISplitter1* prototype){
    this->prototype_ = prototype;
  }

  void Button_click(){
    ISplitter1* splitter = prototype_->clone();
    splitter->split();
    delete(splitter);
  }
};

上面的类中的 ISplitter1* prototype_; 是专门用于创建对象用的,在这个设计模式中它里面的内容不应该被改变。如果或改变了就变味道了

builder 构建器模式

当面对复杂对象的创建工作,通常各自部分的子对象用一定的算法构成, 但是将他们组合在一起的算法却相对稳定
那么在父类中可以封装算法函数。在子类中实现各个步骤例如:

class House {
public:
  void init(){
    BuildPart1();
    for (int i = 0; i < 4; i++) {
      BuildPart2();
    }
    for (int i = 0; i < 2; i++){
      BuildPart3();
    }
  }
  ~House(){};
  protected:
  virtual void BuildPart1() = 0;
  virtual void BuildPart2() = 0;
  virtual void BuildPart3() = 0;
};

class BigHour : public House{
  virtual void BuildPart1(){
    std::cout << "1" << std::endl;
  }
  virtual void BuildPart2(){
    std::cout << "2" << std::endl;
  }
  virtual void BuildPart3(){
    std::cout << "3" << std::endl;
  }
};

int main(){
  House* p = new BigHour;
  p->init();
}

在构建BigHour的时候是,我们只需要重写三个虚函数即可。

class Hous{
public:
  std::string name;
};

class HouseBuilder {
public:
  HouseBuilder(Hous* p){
    pHous_ = p;
  }
  Hous* GetResult(){
    return pHous_;
  }

  virtual void BuildPart1() = 0;
  virtual void BuildPart2() = 0;
  virtual void BuildPart3() = 0;
  protected:
  Hous* pHous_;
};

class StoneHouseBuilder : public HouseBuilder{
public:
  StoneHouseBuilder(Hous* p)
  :HouseBuilder(p)
  {
  }

  virtual void BuildPart1(){
    pHous_->name.append("a");
  }
  virtual void BuildPart2(){
    pHous_->name.append("b");
  }
  virtual void BuildPart3(){
    pHous_->name.append("c");
  }
private:
};

class HourDirector{
  HouseBuilder* pHouseBuilder;
public:
  HourDirector(HouseBuilder* p){
    pHouseBuilder = p;
  }

  Hous* Construct(){
    pHouseBuilder->BuildPart1();
    for (int i = 0; i < 4; ++i) {
      pHouseBuilder->BuildPart2();
    }
    pHouseBuilder->BuildPart3();
    return pHouseBuilder->GetResult();
  }
};


int main(){
  Hous a;
  StoneHouseBuilder builder(&a);
  HourDirector director(&builder);
  std::cout <<  director.Construct()->name << std::endl;
}

还有一个最终版本的,将房子,方法,构建步骤都进行区分的方法:
Hous 用于这个对象的上下文,HouseBuilder是每个的步骤,HourDirector用于封装步骤

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值