我有一个单例类World
。(它不需要是单例的,但它在我的项目中是这样定义的。)
然后我有Component
接口,然后由ConcreteComponent1
, ConcreteComponent2
等实现。这些都实现了一些很好的方法,比如decorateTheWorld
。
在某个时刻,World
实例将遍历它的所有子Compontent
,并要求它们通过调用decorateTheWorld
来修饰自己。
这种方法的问题是World
,或者World
之外的东西需要知道World
可以拥有的任何类型的Component
,因为Component
实例需要在某个时候以某种方式创建。
(new ConcreteComponent1())->registerInTheWorld()
(new ConcreteComponent2())->registerInTheWorld()
(new ConcreteComponent3())->registerInTheWorld()
…和我不想求助于反射。
那么,是否有任何设计模式可以使注册部分自动开箱?还是说我的要求是不可能的?
如果组件实现了一个公共接口,你的世界就不需要知道具体的组件,只需要知道接口。
请看这个例子(c#):
public interface IComponent
{
void decorateTheWorld();
}
public class ComponentA : IComponent
{
public void decorateTheWorld() { /* ... */ }
}
public class ComponentB : IComponent { /* ... */ }
在你的World class中,假设_components
是IComponent
s的集合:
foreach(IComponent comp in _components)
comp.decorateTheWorld();
现在,如果您不想手动"查找"组件,您可以从已加载的程序集中获取所有类型,并找到实现IComponent
的组件,然后使用Activator.CreateInstance
实例化它们。
由于World是单例的,我建议World将持有一组组件,并且在其构造函数中的任何组件都将在单例中注册。所以单例会在不知道子类型的情况下进行迭代
当遇到类似的问题时,我采用了这种方法,如下所示:
创建一个包含所有组件的数组(不是作为具体的实现)。
Array<Components> componentsAttributeInWorld
然后使用您自己创建的创建方法来一次创建一个或多个组件。使用for迭代方法一次创建多个
void createObjectType:(String)nameOfConcreteObjectClass AndCount:(int)numberOfObjects {
for (int i=0; i<numberOfObjects; i++) {
Component *comp = [[Class getClassWithName:nameOfConcreteObjectClass] new];
[componentsAttributeInWorld addObject:comp];
}
}
之后,对象在数组/列表中,您可以再次使用foreach对它们进行迭代。在Objective-C中,你可以动态测试组件真正是哪个类,然后为那个具体实现做一些特殊的方法。在Java中,你甚至可以为字符串使用switch。
…
for (Component *c in componentsAttributeInWorld) {
if ([c isClass:@"ConcreteComponent1"]) {
c.color = ccRED;
else if ([c isClass:@"ConcreteComponent2"]) {
c.size = ccsize(1,2,1);
}
}
…
所以你只需要处理数组,然后排序是不相关的(我用它来知道哪个对象是最老的),然后你可以使用一个集合,这可能会更快!