具体类型还是接口?

时间:2009-01-02 23:52:15

标签: c++

我有以下用例,很多代码紧密耦合在一个具体类型上(比如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) {
    ...
}

5 个答案:

答案 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)

如果您在运行时检查和/或打开类型,您可能需要考虑使用运行时类型信息(如果它可用于您的编译器)。它确实增加了一些开销,但它可以在不创建或维护自定义方法的情况下完成您尝试的操作。

与纯粹主义者不同,我实际上并不是“将功能放在类中,因此您可以使用多态来绕过类型切换”。两者都是有效的方法(虽然“在课堂上”方法并不总是可行的,和/或在概念上是干净的)。

相关问题