设计模式--工厂模式

使用场景

工厂模式应用很广,重构场景:

1. 冗长switch

如果case比较多而且每个case处理处理程序比较复杂(即使将其封装到函数也不容易管理,而且可读性不高,每次要重新阅读case),都可以通过"简单工厂模式"优化:将

//优化前
{
switch(cmd) {
case HTTP_REQ_CMD: 
	process_http_req(); break;
case RPC_REQ_CMD:
	process_rpc_req(); break;
case:...
}
//优化后
class RequestProcess {
public: virtual bool process() = 0; 
};
class HttpRequestProcess : public RequestProcess {
public: virtual bool process() {}
};
class RpcRequestProcess : public RequestProcess {
public: virtual bool process() {}
};

class RequestProcessFactory {
public:	static RequestProcess* createProcessor(int cmd) {
			RequestProcess* processor = nullptr;
			switch(cmd) {
			case HTTP_REQ_CMD: 
				processor = new HttpRequestProcess(); break;
			case RPC_REQ_CMD:
				processor = new RpcRequestProcess(); break;
			}
			return processor;
	}
};
{
//业务处理
RequestProcess* processor = RequestProcessFactory::createProcessor(cmd);
if (processor) {
	processor->process();
} else {
	LOG("process is null");
}
}
}

简单工厂模式

一个工厂类生产一类产品(属于一个继承类簇),在工厂方法createObject里传入产品参数就new出指定的产品,产品参数一般是类名和构造对象时需要的构造函数实参。

class Factory{
public: 
static BaseRequest* createObj(string name) {
	if (name == "HttpRequest") {
		return new HttpRequest;
	} else if (...) {
		...
	}
}
};
BaseRequest
make_req()
HttpRequest
make_req()
TcpRequest
make_req()
RpcRequest
make_req()
RequestFactory
BaseRequest* createObj()

缺点:当增加新的业务场景,需要添加新的请求类,定义完子类后还要修改工厂类,违背开闭原则(只修改提供方,不修改适用方)。

改进1:使用反射

为了不修改工厂类,我们可以把实例化对象的部分拿出来(毕竟同一类簇的类也可能有不同的实例化方法),并利用map做类名到实例化方法的映射,每定义一个类,就注册其实例方法。

namespace src {
//定义Class来存储类名所对应类的实例化方式,并提供注册接口
typedef void* (*instance_func)();
class Class {
public:
    static void* new_instance(std::string class_name) {
        auto iter = _class_map.find(class_name);
        if (iter == _class_map.end()) {
            return NULL;
        }
        return iter->second();
    }

    static void register_class(std::string class_name, instance_func func) {
        _class_map[class_name] = func;
    }
private:
    static std::map<std::string, instance_func> _class_map;  //需要在cpp文件中初始化
};
}
}
//通过宏定义,每定义一个类就注册其实例方法
#define REGISTER_CLASS(class_name) \
    namespace { \
    void* class_name##instance_func() { \
        return new (std::nothrow) class_name; \
    } \
    __attribute__((constructor)) void class_name##register_class() { \
        src::Class::register_class(#class_name, class_name##instance_func); \
    } \
    }

那么工厂类就固定了,为了方便也可以使用宏定义:该类簇的工厂方法。

#define DEFINE_FACTORY(base_class) \
    class base_class##Factory { \
    public: \
        static base_class* get_instance(std::string class_name) { \
            void* ptr = src::Class::new_instance(class_name); \
            return (base_class*)ptr; \
        } \
    };

当定义基类BaseRequest是,要注册类的实例化方法,同时定义工厂类,子类定义时只需注册类的实例化方法。

//base_request.h
class BaseRequest {};
REGISTER_CLASS(BaseRequest)
DEFINE_FACTORY(BaseRequest)
//http_request.h
class HttpRequest {};
REGISTER_CLASS(HttpRequest)
//rpc_request.h
class RpcRequest {};
REGISTER_CLASS(RpcRequest)

NOTE:
简单工厂模式是用来生产同一类簇的对象
为解决不同子类有不同实例化方法问题,将类名和相应的实例化方法存到map中。
由于存储行为应该在main函数之前执行,因此要靠宏定义的__attribute__(constructor)来实现

改进2: 工厂方法

工厂方法

一个工厂只生产一个类的对象的方式,产品在一个类簇,相应工厂类也是一个类簇。

BaseRequest
make_req()
HttpRequest
make_req()
TcpRequest
make_req()
RpcRequest
make_req()
RequestFactory
BaseRequest* createObj()
HttpRequestFactory
TcpRequestFactory
RpcRequestFactory
class HttpRequestFactory : public RequestFactory {
public: 
static HttpRequestFactory* createObj() {
	return new HttpRequestFactory;//只生产一个类的对象
}
}

缺点:当新增业务场景时,不仅要定义子类,还要定义相应的工厂类,类数目成倍增加,增加编译难度。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值