我有以下用例,很多代码紧密耦合在一个具体类型上(比如Concrete1)。后来想通了具体的类型需要改变,所以定义了一个接口。 E.g
Class ABC {
virtual int foo() = 0;
virtual int getType() = 0;
}
class Concrete1 : public ABC {
int foo() {
... }
int getType() {
return 1;
}
}
class Concrete2 : public ABC {
int foo() {
... }
int getType() {
return 2;
}
}
静态工厂模式用于创建对象。因此,创建对象new Concrete1的所有位置都将替换为ABCFactory :: createType()。
现在代码中有很多地方我需要检查createType返回的对象是否是Concrete1或Concrete2,并相应地执行相关逻辑(因此代码中有很多if else :()。
我希望在代码中避免使用其他许多内容作为此更改的一部分。有什么建议?
困扰我的事情是
if (abc.getType() == 1) {
...
} else if (abc.getType() ==2) {
...
}
答案 0 :(得分:9)
使用接口的全部意义在于您可以使用多态,这意味着您永远不必检查实例的类型。这样做是一个非常大的代码味道(见Fowlers Refacotring)。将条件逻辑移动到具体类,并添加te函数,将其处理到接口
编辑(添加代码示例,因为初始帖子是从手机完成的):
您正在尝试:
void Main(string[] args)
{
Bird bird = BirdFactory.GetPigeon();
if (bird.GetType().Equals(typeof(Duck)))
{
Console.WriteLine("quack");
}
else if (bird.GetType().Equals(typeof(Pigeon)))
{
Console.WriteLine("coo coo");
}
}
相反,请尝试:
interface Bird
{
void Speak();
}
class Duck : Bird
{
void Speak()
{
Console.Write("quack");
}
}
class Pigeon : Bird
{
void Speak()
{
Console.Write("coo coo");
}
}
void Main(string[] args)
{
Bird bird = BirdFactory.GetPigeon();
bird.Speak();
}
答案 1 :(得分:2)
将...
置于另一个虚拟方法的实现中:
if (abc.getType() == 1) {
... // A
} else if (abc.getType() == 2) {
... // B
}
将A和B放在这样:
class ABC {
virtual int foo() = 0;
virtual void doIt() = 0; // choose a proper name
};
class Concrete1 : public ABC {
int foo() {
... }
void doIt() {
... // A
}
};
class Concrete2 : public ABC {
int foo() {
... }
void doIt() {
... // B
}
};
将你的if改为
abc.doIt();
正如另一位所说,这正是动态调度的重点!除了更简洁之外,它也永远不会“忘记”处理类型。执行切换时,您可能无法处理特定类型,因为在引入新实现时,您错过了更新该位置的代码。还记得在ABC中有一个虚拟析构函数。
答案 2 :(得分:1)
通过与其他答案的一致,听起来像if / else块中的至少一些代码需要作为新的虚函数在具体类中移动。这将允许您利用多态而不是使用自制反射模式切换类型。
答案 3 :(得分:0)
您可以将检测类外的对象类型的位置移动到类中吗?那样功能(显然取决于具体的类)实际上与相应的类相关联吗?
答案 4 :(得分:0)
如果您在运行时检查和/或打开类型,您可能需要考虑使用运行时类型信息(如果它可用于您的编译器)。它确实增加了一些开销,但它可以在不创建或维护自定义方法的情况下完成您尝试的操作。
与纯粹主义者不同,我实际上并不是“将功能放在类中,因此您可以使用多态来绕过类型切换”。两者都是有效的方法(虽然“在课堂上”方法并不总是可行的,和/或在概念上是干净的)。