我有一个系统,它用C++中复杂的类层次结构来描述许多具有复杂数据和行为的设备。系统的这一部分对这些设备的屏幕表示一无所知,部分原因是解耦,部分原因是许多不同屏幕表示的可能性。
这里MVC Design Pattern/Model-View-Controller用来连接视图和模型,但是作为高级模式,它没有提到在特定语言中镜像模型的类层次结构。
现实需要为每个视图创建一个类的镜像层次结构。不仅如此,我还应该为每个视图创建一个工厂,它将为Model对象创建相应的View类对象。这是大量肮脏和相似的代码。每次有人在Model类层次结构中添加一个新类时(新设备),他必须记得更新工厂,因为知道类SpecficDeviceModel和SpecficDevice2DView之间关系的唯一人是开发者,对于编译器,它们是独立的类,当然可以。
有些人要求提供这种"肮脏和类似代码"的例子,所以下面是工厂代码的总体思路:
NodeView* ViewNodesFactory(NodeModel* nodeModel) {
std::string class_name = typeid(*nodeModel).name();
class_name = class_name.substr(sizeof("class ") - 1);
if (class_name == "DeviceType1") { return new DeviceType1View; }
else if (class_name == "DeviceType2") { return new DeviceType2View; }
else if (class_name == "DeviceType3") { return new DeviceType3View; }
assert(0); // Type is not supported
return new DeviceDefaultView;
}
此代码的主要问题:
1.容易在类名中引入印刷错误。
1.每次将类添加到模型中时,都应该更新工厂。
1.类抽取的名称是"hacky"和容易出错的,因为如果有人将类封装在命名空间中,名称将改变并且代码将中断,因此必须使其更加复杂;这里我只展示了一个概念。
1.有了几十个类,这将是经典的"意大利面代码"。
所以这就是我的问题。随着C++最近的20/23创新,有没有什么方法可以简化这个任务?有没有一种方法可以用许多视图类来表示许多模型类,而不需要大量的"连接"代码?
- 保留**:
当然,我可以写一个复杂的宏,将用于代替声明的意见,将履行工厂数据库。
当然,我可以根据我的命名约定编写python脚本来更新Factory。
但对我来说,这些都是复杂的"hacky"变通方法。在C中有什么直接的方法来解决这个问题吗?据我所知,我们在C中仍然没有这样做的反射。
1条答案
按热度按时间hec6srdp1#
一个相当简单的改进是在模型的基类
NodeModel
中有一个虚拟工厂方法create_view
,然后工厂方法可以委托给被覆盖的方法,因此,当你引入一对新的具体模型/视图时,你永远不必接触工厂方法。下面是一个粗略的例子:
https://godbolt.org/z/oK77fMzhf
缺点是,模型不是独立于视图的。如果你想让模型完全不受视图的影响,并且保持对同一个模型使用不同视图的可能性,你必须能够在运行时注册要创建的视图的类型。为了能够做到这一点,你可以存储一个
unordered_map
,它具有std::type_index
作为键和(类型擦除的)工厂方法作为值。下面是一个例子,其中的工厂是一个单例函子。
https://godbolt.org/z/Wcs4hxE3e
注意,这里没有涉及到C20/C23的魔力。第二个例子只是为了方便而使用C++20,因为使用了
unordered_map::contains
方法。我不认为概念/自动参数对你的使用场景有多大用处:您可以摆脱一些与类型擦除工厂方法和动态调度有关的开销,但我假设您仍然需要能够在异构容器中存储模型和视图,因此无论如何您仍然需要多态性。