C++利用反射和简单工厂模式实现业务模块解耦

1. 业务说明

为了便于说明,举一个简单的例子。假设现在有一个项目需要建立一个和银行交互的平台,目前只接入工商银行,后续接入其他银行,每个银行的业务都有差异,报文格式可能也不一致。

这里只列举几个简要的流程,仅包括拼报文,发送报文,接收报文,解析报文,其余整体架构以及后续处理等内容省略。

2. 初步设计

创建一个银行交互类 BankOpt,包括四个函数:

int setMsg();       //拼报文
int sendMsg();      //发送报文
int getMsg();       //接收报文
int parseMsg();     //解析报文

然后在每个函数中通过if-else来判断具体是哪一个银行,之后进行相应的处理。

这种设计在刚开发的时候非常方便,代码量少,但是如果后续需要接入另外一个银行时就需要改动BankOpt类,不符合设计模式中的开放-封闭原则。而且单个函数中将来可能会有大量的if-else,使代码可读性下降。

3. 简单工厂模式

通过简单工厂模式,我们可以创建一个专门的工厂类用于实例化一个合适的银行交互类,只需要这个银行交互类具有共同的接口即可。

首先,为了实现更好的复用,把各个银行交互类中相同的部分抽象出来,形成一个银行交互基类,代码如下:

class BaseBank
{
public:
    virtual int setMsg() = 0;
    virtual int sendMsg() = 0;
    virtual int getMsg() = 0;
    virtual int parseMsg() = 0;
};

这里仅仅声明了四个纯虚函数,具体的业务逻辑在子类中实现。

创建两个银行交互子类GSBank(工商银行)和RMBank(人民银行),继承BaseBank,实现四个虚函数。

  • 创建一个工厂类
class BankFactory
{
public:
    BaseBank* createBank(const string& bank_name) {
    if (bank_name == “GSBank”)
        return new GSBank();
    else if (bank_name == “RMBank”)
        return new RMBank();
    }
};

工厂类中有一个createBank函数,用于根据银行编码创建相应的实例并返回其基类指针,这样我们只需要通过基类指针调用相关函数即可。

  • 在主流程中调用
BankFactory bf;
BaseBank* t = (BaseBank*)bf.createBank(bank_name);
if (t == NULL) {
    cout << "银行编码错误!" << endl;
    return 2;
}
t->setMsg();
t->sendMsg();
t->getMsg();
t->parseMsg();
  • 优缺点

    利用简单工厂模式,当我们后续接入另外的银行时,只需要添加具体的银行交互类,实现业务函数,然后在工厂类的createBank函数中添加一个else if子句。相对于原来的设计已经改进很多了,但是仍然需要修改原来的工厂类的代码,没有彻底实现解耦。

4. 反射

反射在java的一些框架中使用的比较多,而且用起来非常方便。C++本身并不支持,但是我们可以模拟一些简单的特性。

我们需要一种能够根据字符串动态获取对应的银行交互类的实例的方法。这样在工厂类的createBank方法中就可以根据字符串直接获取对应银行交互类的实例,而不需要再每次通过新增else if 子句来新增一个银行接口。

也就是说,利用反射和简单工厂模式,下次当我们需要新增一个银行接口的时候只需要新增一个银行交互类即可,不需要修改原来的任何代码,实现了业务上的解耦。

  • 如何在C++中实现反射

    1. 需要一个全局的map用于存储类的信息以及创建实例的函数
    2. 需要反射的类需要提供一个用于创建自身实例的函数
    3. 利用类的静态变量在程序启动的时候会进行初始化来在全局map中将类名及创建实例的函数存入map中

相关代码如下:

typedef void* (*register_func)();

class Class
{
public:
static void* newInstance(const string& class_name) {
map<string, register_func>::iterator it = m_register.find(class_name);
    if (it == m_register.end())
        return NULL;
    else
        return it->second();
}
static void registerClass(const string& class_name, register_func func) {
    m_register[class_name] = func;
}

private:
    /* key is class name and value is function to create instance of class */
    static map<string, register_func> m_register;
};

class Register
{
public:
    Register(const string& class_name, register_func func) {
        Class::registerClass(class_name, func);
    }
};

#define REGISTER_CLASS(class_name) \
    class class_name##Register { \
    public:         static void* newInstance() {             return new class_name;         }     private:         static const Register reg;     };const Register class_name##Register::reg(#class_name,class_name##Register::newInstance);

还需要修改工厂类的createBank函数,利用Class的newInstance函数来创建实例:

BaseBank* createBank(const string& bank_name) {
        return (BaseBank*)Class::newInstance(bank_name);
}

Class类中的m_register变量是static类型的map,相当于全局变量。

newInstance函数,传入类名,查找map,调用回调函数,返回一个对应类的实例。

registerClass函数传入类名和用于创建实例的回调函数并将信息存入全局的map中。

Register类只有一个构造函数,会调用Class的registerClass函数完成注册。

利用宏定义,在每一个需要反射的类后面额外增加一个类,其中有一个Register类型的static const变量,这样在程序启动的时候就会完成初始化调用Register类的构造函数,完成注册。

之后只需要在需要反射的类,例如在工商银行交互类 GSBank 后面加上一条宏定义:

REGISTER_CLASS(GSBank) 就可以通过工厂类传入”GSBank”字符串获得工商银行交互类的实例。

5. 测试

通过传入不同的银行编码,会实例化不同的银行交互类,并且执行其对应的函数。

如果需要增加新的银行接口,例如农业银行,只需要新增一个NYBank类,实现具体的业务逻辑,不需要改动原来的任何代码,传入NYBank字符串,就会执行农业银行相关的处理流程。

时间: 2024-10-10 16:47:57

C++利用反射和简单工厂模式实现业务模块解耦的相关文章

有关反射和简单工厂模式的简单实现

先抛出两个概念,反射机制和简单工厂模式. 一句话谈谈自己的理解 反射机制就是由参数(包名类名的字符串),获取具体类的属性方法.简单工程模式就是由一个类作公共出口来生成其他类的实例,父类子类生成模式的简单应用,可以由参数来决定具体需要的实例.往下看,是我搜到的解释,相对完善一点. 什么是反射机制? JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意方法和属性:这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制.上

利用接口实现简单工厂模式

1 package com.wisezone.factory; 2 3 /** 4 * 使用接口实现一个水果工厂 5 * @author 王东海 6 * @2017年4月16日 7 */ 8 public interface Fruit 9 { 10 void eat(); 11 } 1 package com.wisezone.factory; 2 3 /** 4 * 苹果 5 * @author 王东海 6 * @2017年4月16日 7 */ 8 public class Apple im

反射vs简单工厂模式

interface Computer { void printpc(); } class lenovo implements Computer { @Override public void printpc() { System.out.println("选择lenovo电脑"); } } class Deil implements Computer{ @Override public void printpc() { System.out.println("选择Deil电脑

设计模式之_简单工厂模式、工厂方法模式、抽象工厂模式 、策略模式、策略与工厂的区别(转)

一.前言 话说十年前,有一个爆发户,他家有三辆汽车(Benz(奔驰).Bmw(宝马).Audi(奥迪)),还雇了司机为他开车.不过,爆发户坐车时总是这样:上Benz车后跟司机说“开奔驰车!”,坐上Bmw后他说“开宝马车!”,坐上 Audi后他说“开奥迪车!”.你一定说:这人有病!直接说开车不就行了?!而当把这个爆发户的行为放到我们程序语言中来,我们发现C语言一直是通过这种方式来坐车的 幸运的是这种有病的现象在OO语言中可以避免了.下面以Java语言为基础来引入我们本文的主题:工厂模式! 二.简介

简单工厂模式的实现

枚举+反射实现简单工厂模式 定义接口: public interface IAnimal { public void eat(); } 具体类: public class Pig implements IAnimal { public void eat() { System.out.println("pig eat"); } } public class Dog implements IAnimal { public void eat() { System.out.println(&q

项目设计之一------简单工厂模式利用

简单工厂模式可以结合反射进行实现,这样的解耦更好 项目设计之一------简单工厂模式利用,布布扣,bubuko.com

Java反射+简单工厂模式总结

除了 new 之外的创建对象的方法 通过 new 创建对象,会使得程序面向实现编程,先举个例子,某个果园里现在有两种水果,一种是苹果,一种是香蕉,有客户想采摘园子里的水果,要求用get()方法表示即可 一般情况下,最直接的写法为: public class Apple { public void get() { System.out.println("得到苹果"); } }   public class Banana { public void get() { System.out.p

终极版:由简单工厂模式,升级到抽象工厂模式(用到反射)

前面两个已经学习简单三层到简单工厂模式的变化,但是简单工厂模式还是有个缺点,就是简单工厂中集合了所有的实例的创建.也不是很好. 现在想到使用抽象工厂的方式来实现这个: 我们在程序集中加上下面的代码: <appSettings> <!--命名空间--> <add key="DALNameSpace" value="DAL"/> <!--程序集--> <add key="DALAssembly"

【iOS开发系列】用简单工厂模式理解OC反射机制

// 在iOS开发中,简单工厂模式使用得并不多.但是.我认为这是OC反射机制很好的一个例子, // 所以本文将以计算器为例,讲解简单工厂模式和OC的反射机制. // [简单工厂模式的实质是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类( // 这些产品类继承自一个父类或接口)的实例.该模式中包含的角色及其职责:工厂角色.抽 // 象产品角色.具体产品角色] // --百度百科 简单工厂模式 // 上面这句话可能不怎么好理解,我在网上找到了一个例子,可能例子本身不能完全解释这个 // 设