工厂模式
工厂模式属于创建型模式,大致可以分为三类,简单工厂模式、工厂方法模式、抽象工厂模式。
简单工厂模式
简单工厂模式的实质是由一个工厂类根据传入的参数,动态决定应该创建哪一类产品类(这些产品类继承自一个父类或接口)的实例。假设有一个工厂,它能生产出A、B两种产品。当客户需要产品的时候一定要告诉工厂是哪种产品,是A还是B。当新增加一种新产品的时候,便需要修改工厂的类。
工厂方法模式
简单工厂模式的缺点是当新增加产品的时候需要修改工厂的类,这违反了开放封闭原则,即类、模板、函数可以扩展,但是不可以修改。工厂方法模式,是指定义一个用于创建对象的接口,让子类决定实例化哪一个类。现在有A、B两种产品,那便开两个工厂,
工厂A负责生产A产品,工厂B负责生产B产品。客户不需要告诉工厂生产哪种产品,只需要告诉工厂生产即可。
抽象工厂模式
工厂方式模型的缺点是一个工厂只能生产一种产品,比如A工厂想生产A1、A2产品,B工厂想生产B1、B2产品。抽象模式提供一个创建一系列相关的接口,无需指定它们具体的类。
实例操作
下面,以抽象工厂模式为例实际演示工厂模式的威力。
背景:可适配地实现两个变量的多种类型运算方式,包括加法、减法等等。
数据文件:
{
"add":{
"operation_name": "AddOperation",
"a" : 2,
"b" : 4
},
"sub":{
"operation_name": "SubtractionOperation",
"a" : 10,
"b" : 3
}
}
基础类:
#include "base_operation.h"
namespace searcher {
BaseOperationRegistry* GlobalBaseOperationRegistry() {
static BaseOperationRegistry helper;
return &helper;
}
int BaseOperation::Init(float a, float b) { }
void BaseOperation::Run() { }
} // namesapce searcher
#pragma once
#include <string>
#include <unordered_map>
#include <functional>
namespace searcher {
class BaseOperation {
public:
BaseOperation() {}
virtual ~BaseOperation() {}
virtual int Init(float a, float b);
virtual void Run();
public:
float a_;
float b_;
float result_;
};
class BaseOperationRegistry {
public:
using BaseOperationFactory = std::function<BaseOperation*(void)>;
using BaseOperationFactoryMap = std::unordered_map<std::string, BaseOperationFactory>;
public:
BaseOperationRegistry() {}
void Register(const std::string &name, const BaseOperationFactory &factory) {
base_operation_factory_map_[name] = factory;
}
BaseOperation* Create(const std::string &name) {
auto it = base_operation_factory_map_.find(name);
if (it != base_operation_factory_map_.end()) {
return it->second();
}
return nullptr;
}
private:
BaseOperationFactoryMap base_operation_factory_map_;
};
BaseOperationRegistry* GlobalBaseOperationRegistry();
class BaseOperationHelper {
public:
using BaseOperationFactory = std::function<BaseOperation*(void)>;
using BaseOperationFactoryMap = std::unordered_map<std::string, BaseOperationFactory>;
public:
BaseOperationHelper(const std::string &name, const BaseOperationFactory &factory) {
GlobalBaseOperationRegistry()->Register(name, factory);
}
private:
static BaseOperationFactoryMap base_operation_factory_map_;
};
#define REGISTER_BASE_OPERATION(name, factory) \
static BaseOperationHelper helper_obj##__COUNTER__(name, factory);
#define REGISTER_BASE_OPERATION_SIMPLE(name, type) \
REGISTER_BASE_OPERATION(name, []() -> type* {return new type(); })
} // namespace searcher
通用接口:
#include <iostream>
#include <fstream>
#include "json/json.h"
#include "general_operation_processor.h"
#include "base_operation.h"
namespace searcher {
int GeneralOperationProcessor::Init(std::string &json_file)
{
std::ifstream ifs(json_file.c_str());
if (ifs.fail()) {
return -1;
}
Json::Reader reader;
Json::Value root;
if (!reader.parse(ifs, root, false) || not root.isObject()) {
return -1;
}
try
{
const std::vector<std::string>& vecs = root.getMemberNames();
for (unsigned int i = 0; i < vecs.size(); ++i)
{
std::string id = vecs[i];
const Json::Value& jv = root[id.c_str()];
if (!jv.isMember("operation_name") || !jv.isMember("a") || !jv.isMember("b")) {
continue;
}
std::string operation_name = jv["operation_name"].asString();
float a = jv["a"].asDouble();
float b = jv["b"].asDouble();
BaseOperation* operation = GlobalBaseOperationRegistry()->Create(operation_name);
if (nullptr == operation) {
continue;
}
if (operation->Init(a,b) != 0) {
delete operation;
continue;
}
auto* operation_profile = new OperationProfile;
operation_profile->id = id;
operation_profile->a = a;
operation_profile->b = b;
operation_profile->operation_name = operation_name;
operation_profile->op.reset(operation);
operation_profile_map_[id].reset(operation_profile);
}
}
catch(const std::exception& e) {
return -2;
}
return 0;
}
void GeneralOperationProcessor::Run()
{
for (auto iter = operation_profile_map_.begin(); iter != operation_profile_map_.end(); ++iter) {
const auto &profile = iter->second;
profile->op->Run();
}
Print();
}
void GeneralOperationProcessor::Print() const
{
for (auto iter = operation_profile_map_.begin(); iter != operation_profile_map_.end(); ++iter) {
const auto &profile = iter->second;
std::cout << "operation:" << profile->operation_name
<< " ,a:" << profile->op->a_
<< " ,b:" << profile->op->b_
<< " ,result:" << profile->op->result_ << std::endl;
}
}
} // searcher
#pragma once
#include <memory>
#include <string>
#include <unordered_map>
#include "base_operation.h"
namespace searcher {
class BaseOperation;
struct OperationProfile {
std::string id;
std::string operation_name;
float a = 0.f;
float b = 0.f;
std::unique_ptr<BaseOperation> op;
};
class GeneralOperationProcessor {
public:
int Init(std::string &json_file);
void Run();
void Print() const;
private:
std::unordered_map<std::string, std::unique_ptr<OperationProfile>> operation_profile_map_;
};
} // searcher
子类-加法运算:
#include "add_operation.h"
namespace searcher {
int AddOperation::Init(float a, float b)
{
a_ = a;
b_ = b;
return 0;
}
void AddOperation::Run() {
result_ = a_ + b_;
}
} // searcher
#pragma once
#include "base_operation.h"
namespace searcher {
class AddOperation : public BaseOperation {
public:
AddOperation() {}
virtual ~AddOperation() {}
virtual int Init(float a, float b);
virtual void Run();
};
REGISTER_BASE_OPERATION_SIMPLE("AddOperation", AddOperation);
}; // searcher
子类-减法运算:
#include "subtraction_operation.h"
namespace searcher {
int SubtractionOperation::Init(float a, float b)
{
a_ = a;
b_ = b;
return 0;
}
void SubtractionOperation::Run() {
result_ = a_ - b_;
}
} // searcher
#pragma once
#include "base_operation.h"
namespace searcher {
class SubtractionOperation : public BaseOperation {
public:
SubtractionOperation() {}
virtual ~SubtractionOperation() {}
virtual int Init(float a, float b);
virtual void Run();
};
REGISTER_BASE_OPERATION_SIMPLE("SubtractionOperation", SubtractionOperation);
}; // searcher
最后,贴上g++运行指令:
g++ -std=c++11 -g -I../../json/include/ -L../../json/lib/ base_operation.cpp add_operation.cpp subtraction_operation.cpp general_operation_processor.cpp main.cpp -o main -ljson