[笔记] 模拟java Class.forName

[笔记] 模拟java Class.forName

反射

从类型系统的角度来看,当需要在两个不同的系统中传递信息(数据)时,接收方需要知道发送方发送的数据的内部构造(数据成员,方法等),接收方在在回过头"找自己的类型"的这个过程,可以理解为反射。类似地,也可以在发送方这边完成接收方"找到类型"的这一动作,这也需要发送方能知道自身对象的内部构造。

比如实际例子中的java和sql,以及java和json等。

个人从“类型”的角度来表达一下我理解的反射。

某个系统A是基于对象的,对象里的字段都是有明确类型的,可以是int,double,或者某个对象的reference。

系统A的数据传递到了系统B。但是系统B可能是函数式的,数据的表现方式只是一个列表,而不是对象,数据的类型也不知道了。

数据类型不知道是不行的,这个列表要把自己找回来,它回过头“找寻自己的类型”的过程,就是反射。

实际的例子是,A == Java, B == SQL。系统间的分界好像水面,数据看着自己反射出的倒影发现:“哦,原来我是长这个样子的!

模拟java Class.forName

Java 有一个非常突出的动态关联机制:反射,在 Java 的情况下意味着类,我们可以在运行时加载、检测和使用,在编译时完全未知。换句话说,Java 程序可以加载一个名称只有运行时知道的类,了解其完整构造(但不了解其方法定义),并生成其对象实体,或设置其字段值,或调用其方法。


String className = "MyClassA";
class c = Class.forName(className);
factory = (ExampleInterface)c.newInstance();

首先,很容易想到使用简单的工厂模式来实现。

struct Object {
	virtual std::string ToString() { return "MyClass"; }
	virtual ~Object() {}
};

struct A : public Object {
	virtual std::string ToString() override { return "A"; }
};

struct B : public Object {
	virtual std::string ToString() override { return "B"; }
};

Object *FactoryCreate(const std::string& className) {
	if (className == "A") { return new A; }
	else if (className == "B") { return new B; }
	else { return nullptr; }
}

然后我们这样使用它:

int main() {
    auto ptr1 = FactoryCreate("A");
    auto ptr2 = FactoryCreate("B");
    std::cout << ptr1->ToString() << '\n';
    std::cout << ptr2->ToString() << '\n';
    delete ptr1;
    delete ptr2;
    return 0;
}

看起来我们好像解决了问题,但是当我们需要创建一个新的类或修改某一个类,那么我们的FactoryCreate就不得不修改了。比如我们新增一个C类继承子Object,或者增加了一个新的基类Object2以及其派生类A’和B’,直接使用template function是不可行的,因为如果我们有新的基类,那么还需要再添加对应的if/else代码。

使用工厂模式+回调

在上述方法中,上下文是:

  • factory中需要存在一个映射,字符串和创建对应类的方法
  • factory提供一个接口,我们输入字符串,返回一个指向对应类的指针
  • 在我们的自定义类中,如果支持reflection,应当支持自动在factory map中注册它的名字和方法(创建类的函数)
#include <iostream>
#include <string>
#include <map>
#include <cassert>

struct ClassInfo;
struct Object
{
    Object() {}
    ~Object() {}
    virtual std::string ToString()
    {
        return "Object";
    }
    static void Register(ClassInfo *ci);
    static Object *CreateObject(const std::string &name);
};

struct ClassInfo
{
    using ObjectConstructorFn = Object *(*)(void);
    ClassInfo(std::string name, ObjectConstructorFn ctor) : m_className(std::move(name)), m_objectConstructor(ctor)
    {
        Object::Register(this);
    }
    virtual ~ClassInfo() {}

    Object *CreateObject() const
    {
        return m_objectConstructor ? m_objectConstructor() : nullptr;
    }

    std::string m_className;
    ObjectConstructorFn m_objectConstructor;
};

std::map<std::string, ClassInfo *> classInfoMap;
void Object::Register(ClassInfo *ci)
{
    assert(ci != nullptr);
    if (classInfoMap.find(ci->m_className) == classInfoMap.end())
    {
        classInfoMap.insert({ci->m_className, ci});
    }
}

Object *Object::CreateObject(const std::string &name)
{
    if (auto iter = classInfoMap.find(name); iter != classInfoMap.end())
    {
        return iter->second->m_objectConstructor();
    }
    return nullptr;
}

struct A : public Object
{

    static Object *CreateObject()
    {
        return new A;
    }

    virtual std::string ToString() override
    {
        return "A";
    }

protected:
    // 方法可重载, 因此这里的注册并不完美, 且每个继承类型都需要加上改行代码来注册
    inline static ClassInfo my_classInfo{std::string{"A"}, A::CreateObject};
};


struct B : public Object
{

    static Object *CreateObject()
    {
        return new B;
    }

    virtual std::string ToString() override
    {
        return "B";
    }

protected:
    // 方法可重载, 因此这里的注册并不完美, 且每个继承类型都需要加上改行代码来注册
    inline static ClassInfo my_classInfo{std::string{"B"}, B::CreateObject};
};

int main()
{
    auto ptr1 = Object::CreateObject(std::string{"A"});
    assert(ptr1 != nullptr);
    std::cout << ptr1->ToString() << '\n';

    auto ptr2 = Object::CreateObject(std::string{"B"});
    assert(ptr2 != nullptr);
    std::cout << ptr2->ToString() << '\n';

    delete ptr1;
    delete ptr2;
}

reference

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值