使用接口是一种非常简单的方法来删除依赖项,但是当您的某个类需要一个未由接口定义的方法时会发生什么?如果您正在使用构造函数注入或工厂,那么如何在不进行转换的情况下访问该额外方法?这可能吗?
以下是出现此问题的工厂示例。我想做一些不可能的事吗?谢谢你的帮助。
interface IFoo {
int X { get; set; }
int Y { get; set; }
}
public class A : IFoo {
int X { get; set; }
int Y { get; set; }
}
public class B : IFoo {
int X { get; set; }
int Y { get; set; }
int Z { get; set; }
}
public static class FooFactory {
public static IFoo GetFoo(string AorB) {
IFoo result = null;
switch (AorB) {
case "A":
result = new A();
break;
case "B":
result = new B();
break;
}
return result;
}
}
public class FooContainer {
private IFoo foo;
public FooContainer(IFoo foo) {
this.foo = foo;
}
/* What methods would you define here. I'm new to IoC. */
}
public class Main(...) {
int x,y,z;
IFoo fooA = FooFactory.GetFoo("A");
x = foo.X;
y = foo.Y;
IFoo fooB = FooFactory.GetFoo("B");
x = foo.X;
y = foo.Y;
z = foo.Z; /* Does not compile */
z = ((B)foo).Z; /* Compiles, but adds unwanted dependency */
}
答案 0 :(得分:6)
你确实需要施放。这是正常的,有时是必要的。这通常表明事情是错误的。
理想情况是,如果方法/例程接受/返回接口,那么您的逻辑只关心该接口公开的成员。如果在该方法中你发现自己正在检查确切的类型,以便你可以转换为该类型并根据类型调用不同的成员,那么可能是错误的。
假设您有 IContact 界面,实现此功能的一些实体是您的类客户,购买者和承包商。如果你有一个采用IContact的 SendChristmasCard 方法,它应该只关心IContact成员。如果您在此方法中有逻辑,在obj.GetType().ToString
上执行选择案例以确定它是否是客户,那么:
如果方法返回一个接口而你使用该对象,上面仍然适用,但根据我的经验,它可以,然后< / em>,最好忍受铸造。通过“修复”情况添加的复杂功能可能会使其更加复杂。我会说逻辑的进一步向上和非标准,只是采取简单的方法。 SendChristmasCard 显然不是核心功能;如果IContact工厂方法只是方便的方法给你所有的联系人,那么可能只是使用它,传递给 SendChristmassCard(IContact Contact),并在里面检查类型说“它很高兴今年给你买“或者今年给你很好的销售”等等。但如果这是你系统的核心逻辑,你真的需要寻找更好的方法。
但请查看Decorator Pattern,这可能有助于此类情况。
答案 1 :(得分:1)
如果您尝试访问接口无法使用的方法,请不要使用Factory。你显然很难编写一个依赖...所以只需要它(但只有在真的有必要时)。
无需过度复杂化。
尝试强制转换为Object类型而不是接口将引入依赖...但它会隐藏它而不是显然暴露依赖。如果有人在将来更改了Factory并且您的调用返回了不同的Object类型,那么您的代码现在将以非显而易见的方式中断。
答案 2 :(得分:1)
当您遇到向下转换对象的需求时,通常表明API可能会更好。
向下转换抽象类型违反了Liskov Substitution Principle。通常可以通过更改相关接口的样式来解决此问题。而不是公开大量属性和查询(在CQS术语中),而是将注意力转向更强命令的方法。这是Hollywood Principle。
您可以重新定义其对一组命令的行为,而不是让IFoo
公开X和Y属性:
public interface IFoo
{
void DoStuff();
void DoSomethingElse(string bar);
void DoIt(DateTime now);
}
然后,具体实现可以封装他们想要的任何数据(例如X,Y或Z属性),而消费者无需了解它们。
当界面变得太大时,是时候应用Interface Segregation Principle或Single Responsibility Principle。