Proper Architecture for Application
Given an application-wide collection of objects, and many unrelated classes that need frequent access to these objects, what is the best way to provide said access?
Example:
// 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
}
}
}
Assumptions:
Design Requirements and Problems with Other Solutions:
While I'm refactoring legacy code to do this, my main concern is designing the right architecture in the first place. This seems like a very common logical concept, but all the solutions I see fail to address some important aspect of using it for production or have a glaring flaw/tradeoff. Maybe I'm being too picky, but in my experience the right tool for the job has zero drawbacks in that context.
There is one clean, maintainable and testable solution, but you reject it in your requirements:
Dependency injection looks like an unreasonable burden on calling code (given the layering,) and sacrifices too much clarity for my liking
I'm going to ignore that requirement for now. See the end of my answer if you really really want to avoid dependency injection (which I don't recommend).
Designing the collection objects
Designing the collection access mechanism
The solution needs to promote thread-safety
This screams for a factory-like intermediary: Create a factory that provides access to the collection. The factory can then decide when to return a new collection or an existing one. Make sure clients give the collection back when they are finished, so that you know how many clients are using it.
Now all clients access the collection through the factory. They only see the interface, never the real implementation.
Getting a reference to the factory
Now that we introduced the factory, clients don't need to know access the collection directly (statically) anymore. However, they still need to get hold on the factory itself.
Make the factory a dependency by injecting it to the constructors of the clients. This design clearly communicates that the clients depend on the factory. It also enables you to switch out the factory during testing, eg to replace it with a mock.
Note that using dependency injection does not mean you need to use a DI framework. The important thing it to have a clean, well-defined composition root.
Avoiding DI
As I already said, this is not recommended. DI is the basis for clean, decoupled designs that emphasize testability.
If you still want to avoid DI, then modify the above design as follows:
Further notes
Your collections and usage thereof sound a lot like the repository pattern. My design suggestions above are in line with this similarity (eg access collections in a narrow scoped way and "give them back"). I think reading about the repository pattern will help you to get your design right.
链接地址: http://www.djcxy.com/p/89100.html上一篇: 数据使用AWS API网关和Lambda
下一篇: 正确的应用架构