正确的应用架构
给定一个应用程序范围的对象集合,以及需要频繁访问这些对象的许多不相关的类,提供上述访问的最佳方式是什么?
例:
// Object A, stored in collections, used to do useful things
class A
{
...
public:
QString property(const QString& propertyName) {return m_properties.value(propertyName);}
protected:
QHash<QString,QString> m_properties;
}
// Collection class, contains methods to:
// - Access members of collections
// - Add/Remove members from collection
class GlobalCollection
{
public:
// Accessors to collection/collection members
static A* getAs() {return aHash;}
static QHash<QString,A*> getAByKey(const QString& key) {return aHash.value(key);}
static QList<A*> getAsMatchingCriteria(const QString& property, const QString& value)
{
QHash<A*> subsetOfA;
foreach(A* pA, aHash.values())
{
if (pA->property(property) == value)
subsetOfA << pA;
}
return subsetOfA;
}
protected:
QHash<QString,A*> aHash;
}
// Example client class that uses A's to do its job
class Client
{
public:
// This is tied to a button click, and is executed during run-time at the user's whim
void doSomethingNonTrivialWithAs()
{
// Get A* list based on criteria, e.g. "color" == "green"
QList<A*> asWeCareAbout = ???;
// Draw all the "green" A's in a circle holding hands
foreach(A* pA, asWeCareAbout)
{
// Draw a graphical representation of pA
// If pA has "shape" == "square", get a list of all the non-"green" "square" A's and draw them looking on jealously from the shadows
// Else if pA has "shape" == "circle", draw the non-"green" "circles" cheering it on
}
}
}
假设:
其他解决方案的设计要求和问题:
当我重构遗留代码来做到这一点时,我主要关心的是首先设计正确的架构。 这似乎是一个非常普遍的逻辑概念,但是我所看到的所有解决方案都未能解决将其用于生产的一些重要方面,或者存在明显的缺陷/折衷。 也许我太挑剔了,但以我的经验来说,正确的工具在这方面没有任何缺点。
有一个清洁,可维护和可测试的解决方案,但您在需求中拒绝:
依赖注入看起来像调用代码时的不合理负担(给定分层),并牺牲了我的喜欢太多的清晰度
我现在要忽略这个要求。 如果你真的想避免依赖注入(我不推荐),请参阅我的答案的结尾。
设计集合对象
设计收集访问机制
该解决方案需要提升线程安全性
这为一个类似工厂的中介而尖叫:创建一个工厂,提供对集合的访问。 然后,工厂可以决定何时返回新的集合或现有的集合。 确保客户在收集完成后将其收回,以便知道有多少客户正在使用它。
现在所有的客户都通过工厂访问集合。 他们只看到界面,从来没有真正的实现。
获得对工厂的参考
现在我们介绍了工厂,客户不需要知道直接(静态)访问集合。 但是,他们仍然需要掌握工厂本身。
通过将工厂注入到客户的构造函数中来使工厂成为依赖项。 这种设计清楚地表明客户依赖于工厂。 它还使您能够在测试过程中关闭工厂,例如用模拟器替换它。
请注意,使用依赖注入并不意味着您需要使用DI框架。 重要的是它有一个清晰,明确的组合根。
避免DI
正如我已经说过,这不是建议。 DI是强调可测试性的干净,分离设计的基础。
如果你仍然想避免DI,那么修改上面的设计如下:
进一步说明
您的收藏和使用听起来很像存储库模式。 我上面的设计建议符合这种相似性(例如以狭窄范围的方式访问集合并“回馈”)。 我认为阅读有关存储库模式将帮助您获得正确的设计。
链接地址: http://www.djcxy.com/p/89099.html