寻找一种设计模式来取代huuuge如果对象类型

时间:2008-11-20 17:48:57

标签: design-patterns generics dependency-injection

好的,所以我正在寻找一些看起来大致如此的代码:

void DoSomething(object o)
{
    if (o is Sometype1) { 
    //cast o to Sometype and do something to it
    }
    else if (o is Sometype2) {
    //cast o to Sometype2 and do something to it
    }
    ...
    else if (o is SometypeN) {
    //cast o to SometypeN and do something to it
    }
}

现在一种方法是使用作参数的所有对象o实现类似

的接口
interface ICanHaveSomethingDoneToMe
{
    //expose various properties that the DoSomething method wants to access
}

但问题是我不希望我的所有对象都实现这个接口 - 做某事的逻辑并不真正属于他们。我应该使用什么模式来解决这个问题?

我怀疑像

的一系列实现
interface IPropertiesForDoingSomethingTo<T>
{
    //expose various properties that the DoSomething method wants to access
}

可能会更好。我有一个针对我想要做的每个对象类型的实现,但后来我遇到了这个新问题。我需要有一个像

这样的方法
IPropertiesForDoingSomethingTo<T> GetPropsGeneric(T t);

但这是否需要对其进行大规模切换?我应该使用诸如

之类的方法来定义一个类
IPropertiesForDoingSomethingTo<Someobject1> GetProps(Someobject1 t);
...
IPropertiesForDoingSomethingTo<Someobject1> GetProps(SomeobjectN t);

与在运行时无法添加新类型的通用版本相比,这会产生问题。是否有人可以使用GetPropsGeneric中的DI容器解决容器?谢谢!

6 个答案:

答案 0 :(得分:6)

每次看到正在检查对象类型的switch语句(或一系列if语句)时,这都是缺少基类或接口的Big Red Flag。换句话说,代码应该依赖于多态,而不是测试对象类型

如果你不能改变基类或实现一个接口,你可能会留下一个字典来模拟动态调度。在C#中,您可以使用包含转换

的方法的匿名委托

对于属性访问,如果属性不符合并且通过反射访问不是一个选项,则可能需要在上面的方法/委托中提取属性值并将它们传递给泛型函数

答案 1 :(得分:2)

看起来你可能正在使用C#。我相信你可以创建附加到已经建立的类的“扩展方法”。

另一种方法是为每种类型创建处理程序委托,并在对象类型键入的哈希表中存储对委托的引用。

然后你的“DoSomething”方法可以通过传入和执行的对象的类型查找适当的委托。

答案 2 :(得分:0)

一个真实的例子会更有帮助。如果您只是为一系列相关类更改方法的实现,那么,正如@Steven A. Lowe所说,您最好使用多态并使用子类关系。如果课程没有参与“是”关系,那么其他模式如Visitor可能更合适。

答案 3 :(得分:0)

多态性是传递基础对象的答案。但是,它的模板和语义复杂性远远超出你想要的范围。

它需要将您的功能以某种方式分流到派生类和要实现的“虚拟”功能中。

答案 4 :(得分:0)

我认为这更像是面向方面编程方法的问题。

我希望您的DoSomething方法将ICanHaveSomethingDone接口作为其参数。然后,我将定义ICanHaveSomethinhgDone接口,并从中导出实现DoSomethingToMe的sublcasses(每个对象,你想要DoSomething),每个实现类都不同。他们每个人只需要一个你想做某事的类型的构造函数,这样当你去调用DoSomething时,你实际上会调用一个Factory(非常简单,只需从输入类型创建一个ICanHaveSomethingDone类的实例)创建一个实现DoSomethingToMe方法的类的实例,该方法具有适当的底层对象代码。

基本上,以这种方式思考;你要定义一个你想要参数对象实现的接口契约;并以对象和接口的子类的形式定义“装饰”,以实现特定类的接口行为的特定实现(因此履行合同)。通过这种方式,您可以使每个类的DoSomething方法的实现与这些类的源完全分开。

这样做的另一件事;这意味着如果将工厂设置为DI容器,则可以在运行时添加新类型;通过向您的工厂容器中注入您希望能够执行某些操作的新类型,只要您将要执行的操作实现定义为从您的接口和该类派生的类, 你很厉害。如果实现完整的AOP方法,您甚至可以在运行时定义行为而不必实现派生类;定义你的接口,定义行为的行为,并参数化派生类的实现,在运行时将你想要的行为与你传入的对象组合在一起。但这很复杂......: - )

顺便说一下,Spring AOP对这个东西很了不起。我已经读过了。

答案 5 :(得分:0)

我同意Steven,这个问题上下文也提醒我双重调度问题,因此访客模式可能是正确的解决方案。但是,显然您的层次结构缺少某些接口定义。