Abstract Class X Interface
You started creating the class Pet
with common properties among derived classes. Is there any reason not to continue doing this for methods and events? If I pass these joint members to the Pet
already simplifies a lot. Renan suggested to join everything in an interface called Pet
. But you already have this interface. An abstract class is both a class and an interface. The abstract class Pet
is your interface.
Generalize what you can
Follow Renan’s recommendation and turn the methods of sound emission of Pets into something generic. Remember that the sound emission is the unique action, the way the sounds are emitted is that it will vary, that is, the implementation varies. What you did was exactly what is described in link contributed by Joshua Eduardo.
You probably still don’t quite understand the concept of what the interface is. It declares actions and not the mechanism (normally, but we will not make the mechanism being used in other ways, not all language does this), the implementation of these actions. Understand that abstract interfaces and methods of abstract classes define behavior, but do not implement this behavior. Only concrete classes can implement the behaviors. When you treat a bark or a neigh without the abstraction of the ability of animals to emit sounds, you are leaving aside one of the advantages of object orientation which is real abstraction (having an abstraction of bark to implement a bark is an artificial abstraction).
Perhaps all these sound emissions are already included in the method Talk()
and only the different implementations are necessary. At this point I disagree with Renan that each type of Pet
does not need specific classes. You need to be able to make the specific implementations in these classes. The suggested solution would only work if all sound emissions were equal.
If the Talk()
serves another thing, you can create another generic method to denote the action of emitting sounds of pets, Speak()
maybe?.
When you do this, all interfaces, individually, will be implemented in only one class each. Can you tell why this is necessary? If you have a good reason, ok, if you don’t have it, finish it. In general an interface is only interesting when it is used in at least two classes. Future use is not a good reason. If in the future need, there you create the interfaces. There are no problems in creating an interface and putting in an existing class since the design class is right. An existing class can assume a new interface if it already has the desired behavior. This hurts no principle and creates no problems.
I say more. If you can abstract the pairs of methods (do not force the bar, only do it if it is the best to do), Eat
and Recharge
, Sleep
and Maintenance
, Poop
and OilLeak
, you may find that they are the same action with different implementations.
Future implementation
If you ever need one HybridPet
implementing some methods (and events obviously) unique to the AnimalPet
And also some unique methods of RoboticPet
, then you create the IAnimalPet
which will be used in the class AnimalPet
and in the HybridPet
and the IRoboticPet
which will be used in the RoboticPet
and HybridPet
. This is if they really help something. You only need two interfaces.
Completion
Have you noticed that you need zero interfaces? In your case, you have many interfaces. In current modeling, an interface is very.
Don’t forget that in abstract classes, unlike interfaces you can give a standard implementation of the methods if they match some types of pets.
Don’t worry about the future in this case. If you have difficulty creating a consistent interface in the future it is because your model was wrong, not because you failed to create the interface before.
I find your case quite simple and don’t need to make the gambit of making a specialization an exception (and probably generate an exception in Runtime in this case) as suggested by Renan.
If improve the modeling and still have questions post new question to continue helping with the new problem.
+1. I would include: "Being a triple bastard and lying, returning True but ignoring."
– OnoSendai
I agree with the implementation of the method Speak(), But I don’t know, in a way, separate each action into its own interface until it makes sense because it would make it much easier to create secondary interfaces. Imagine two types of "animals", Automaton and Android. They’re both the type Robot (interface) which in turn is a Pet, but each one is more specific than the other.
– Bruno Augusto
An Automaton would be any machine with one or more purpose(s) only(s), whereas an Android could speak and "sleep". And with specific methods on separate interfaces the way it is you can easily achieve this goal without prejudice to the polymorphism because in the eyes of the Application all will be Pet.
– Bruno Augusto
@Brunoaugust general rule: specializing too much in interfaces is a shot in the foot. Just look at how interfaces are used in large frameworks like Java or .NET. In general, interfaces are as comprehensive as possible. Case in point: Icollection.
– Oralista de Sistemas
I’m not saying it’s right, I don’t have the deep grasp to hammer that hard. Nor am I saying that all these interfaces are really essential, that there is even no possibility of extending the scope of one or the other. But that makes a certain sense.
– Bruno Augusto
@Brunoaugusto There are even reasons to have interfaces with only one method (or few), this is not enough to be a big problem but it makes no sense to separate behaviors that are related. I even understand what you are saying, there are reasons to do it this way (I explain in my reply) but at the moment he is not doing it. When he changes the design and you can post another question to help with the new configuration. Then maybe some interfaces are really useful. That would be nice and do this. To see if he got the hang of it or needs more guidance.
– Maniero
@Renan (Shut up and take my +1!) is a pity that we can not favorite answers, one of the best I’ve read here on SO-pt.
– RodrigoBorth
@Renan An object should not publish a method that is not his behavior. If a slug can’t somersault backwards, why does it have a method to trigger this impossible behavior? If the slug publishes this method we are faced with a design error.
– Caffé
I believe it is right at this point that I tried to reach, @Caffé. Again, I’m not saying that the diagram modeling is correct BUT, having each action on a different interface, it’s like arriving at a mall, at those candy stores, and saying "I want this, this, that and a little bit of that other" and each time something different will come out, that does more or less things than the previous without overloading anyone, without publishing unnecessary methods and etc.
– Bruno Augusto
In the case of the slug, it would be best to have at least one interface separating this behavior (or behaviors), otherwise you would be performing a breach of contract. The Principle of Liskov’s replacement talks about it.
– gabrielhof
+1 for humor! hauahuahuahua
– Pedro Laini