Specific type or interface?

I have the following use case, a lot of code that was tightly coupled on a specific type (say Concrete1). Later it turned out that the specific type needs to be changed, so the interface is defined. for example

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;
    }
 }

      

A static factory pattern was used to create the objects. So, all the places where the new Concrete1 object was created are replaced with ABCFactory :: createType ().

Now in the code there are many places where I need to check whether the object returned by createType is concrete1 or Concrete2 and, accordingly, the corresponding logic (so many, if still in the code :().

I want to avoid a lot if still in code as part of this change. Any suggestions?

What worries me is

if (abc.getType() == 1) {
    ...
} else if (abc.getType() ==2) {
    ...
}

      

+1


source to share


5 answers


the whole point of using interfaces is that you can use polymorphism, which means you never have to check what type of instance is. this is a very big code smell (see Fowlers Refacotring). move the conditional logic to concrete classes and add a te function that will handle it in the interface

EDIT (adding example code from the moment the message was created from the mobile):

You are trying to do:



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");
   }
}

      

Try this instead:

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();
}

      

+9


source


Place ...

another virtual method inside the implementation:

if (abc.getType() == 1) {
    ... // A
} else if (abc.getType() == 2) {
    ... // B
}

      

Place A and B like this:

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
    }
 };

      



And change yours if on

abc.doIt();

      

Like another one said that exactly the point of dynamic dispatch! Besides being more concise, it never forgets to handle the type. By executing your switch, you can silently handle a specific type, because you missed updating your code at that point when you introduced a new implementation. Also be aware of the virtual destructor in ABC.

+2


source


Consistent with the other answers, this sounds to me like some of the code in if / else blocks needs to be moved inside concrete classes as a new virtual function. This will allow you to use polymorphism, rather than include types with the reflection pattern at home.

+1


source


Can you move the places where you discover the types of objects outside the class to the class? So the functionality (which seems to be class specific) is actually related to the corresponding class?

0


source


If you are checking and / or including a type at runtime, you may need to use runtime type information if available to your compiler. It adds some overhead, but it does what you are trying to do without creating or maintaining a methodology of its own.

Unlike the purists, I'm not really "putting functionality in a class so you can use polymorphism to get around the switch type." Both are valid approaches (although the "in-class" method is not always possible and / or conceptually clean).

0


source







All Articles