问题陈述
我有一个模型类,看起来像(非常简化;为清楚起见,省略了一些成员和许多许多方法):
class MyModelItem
{
public:
enum ItemState
{
State1,
State2
};
QString text() const;
ItemState state() const;
private:
QString _text;
ItemState _state;
}
它是应用程序的核心元素,用于代码的许多不同部分:
- 它被序列化/反序列化为/从各种文件格式
- 它可以写入或从数据库中读取
- 它可以通过“导入”进行更新,该导入读取文件并将更改应用于当前加载的内存模型
- 用户可以通过各种 GUI 功能对其进行更新
问题是,这个类多年来一直在增长,现在有几千行代码;它已成为如何违反单一责任原则的典型例子。
它具有直接设置“文本”、“状态”等的方法(在反序列化之后)以及从 UI 中设置它们的相同方法集,这些方法具有更新“lastChangedDate”和“lastChangedUser”等副作用. 有些方法或方法组的存在甚至不止两次,每个人做的事情基本相同,但略有不同。
在开发应用程序的新部分时,您很可能使用了五种不同的操作方式中的错误MyModelItem
,这使得它非常耗时且令人沮丧。
要求
鉴于这个历史悠久且过于复杂的类,目标是将它的所有不同关注点分成不同的类,只留下核心数据成员。
理想情况下,我更喜欢这样的解决方案,其中MyModelItem
对象只有const
用于访问数据的成员,并且只能使用特殊类进行修改。
然后,这些特殊类中的每一个都可以包含业务逻辑的实际具体实现('text' 的设置器可以执行类似“如果要设置的文本以某个子字符串开头并且状态等于 'State1',设置它到'State2'”)。
解决方案的第一部分
对于加载和存储由许多MyModelItem
对象和更多对象组成的整个模型,访问者模式看起来是一个很有前途的解决方案。我可以为不同的文件格式或数据库模式实现几个访问者类,并有一个save
andload
方法MyModelItem
,每个都接受这样的访问者对象。
开放式问题
当用户输入特定文本时,我想验证该输入。如果输入来自应用程序的另一部分,则必须进行相同的验证,这意味着我不能将验证移动到 UI 中(无论如何,仅 UI 验证通常是一个坏主意)。但是如果验证MyModelItem
本身发生,我又遇到了两个问题:
- 最初的目标是关注点分离被否定了。所有的业务逻辑代码仍然被“倾倒”到糟糕的模型中。
- 当应用程序的其他部分调用此验证时,该验证的外观必须有所不同。实现不同的验证设置方法是现在的方式,这有一种不好的代码味道。
现在很清楚,验证必须移到 UI 和模型之外,进入某种控制器(在 MVC 意义上)类或类集合。然后这些应该用其数据装饰/访问/等实际的哑模型类。
哪种软件设计模式最适合所描述的案例,以允许以不同的方式修改我的类的实例?
我在问,因为我所知道的模式都不能完全解决我的问题,而且我觉得我在这里遗漏了一些东西......
非常感谢您的想法!