4

I have this out of context scenario, where what I think is good practices leaves me in a situation of both implementing an interface, and using composition to do the implementation.


Imagine the following:

I have a Character with Health and Mana, like so:

interface ICharacter
{
    Health Health { get; }
    Mana Mana { get; }
}

class Character : ICharacter
{
    public Health Health { get; private set; }
    public Mana Mana { get; private set; }

    public Character(Health health, Mana mana)
    {
        this.Health = health;
        this.Mana = mana;
    }
}

I then decide, that Health and Mana should be combined into one object, since they belong together.

interface IResource
{
    Health Health { get; }
    Mana Mana { get; }
}

I change my Character to

interface ICharacter
{
    IResource Resource { get; }
}

class Character : ICharacter
{
    public IResource Resource { get; private set; }

    public Character(IResource resource)
    {
        this.Resource = resource;
    }
}

However, so that clients of Character can access a character's health without saying character.Health.Current and "violating" the principle of least knowledge I want Character to provide this information. And to improve encapsulation I would no longer disclose how Character stores its Health and Mana, like so:

interface ICharacter : IResource
{
}

class Character : ICharacter
{
    private IResource resource;

    public Health Health
    {
        get
        {
            return resource.Health;
        }
    }

    public Mana Mana
    {
        get
        {
            return resource.Mana;
        }
    }

    public Character(IResource resource)
    {
        this.resource = resource;
    }
}

This gets my Character back to having Health and Mana which I like, but Character is now implementing the same interface it is am composed of.


In implementation, this looks quite a lot like the Decorator Pattern, but in intention, they have nothing in common.

Questions

  1. Is this pattern / antipattern of implementing the same interface that a class is composed of recognized, and if so, what is it called?

  2. Would you consider this good a idea over just having a property to IResource? - Why? / why not?

  3. Any situations to be wary off, where this is a definitive no-go?

Sidenote - ICharacter would certainly have more methods, but to shorten it and keeping it concise, I only included the relevant part here.

10
  • 8
    When books and articles refer to "prefer composition over inheritance", they are specifically not talking about interfaces; they're talking about state and behaviour inherited from a base class. As your example demonstrates, interfaces are often a useful tool for using composition instead of inheritance. Commented Apr 12, 2017 at 8:45
  • 2
    Game developers tend to handle such design issues a bit different than business application developers. You might want to ask this question on gamedev.stackexchange.com instead.
    – Philipp
    Commented Apr 12, 2017 at 9:19
  • @BenCottrell, I always thought prefer composition over inheritance was about being able to change the functionality, without changing the class, even in runtime. Implementing an interface has this same restriction as inheriting a class. Commented Apr 12, 2017 at 10:33
  • 1
    @Philipp, This is a business application rewritten to a domain everyone understands. Thanks though. :) Commented Apr 12, 2017 at 10:41
  • 1
    A class implementing an interface cannot change its behavior without being rewritten. Only through composition is this possible. Commented Apr 12, 2017 at 11:18

4 Answers 4

10

Composition over Inheritance, why not both?

The principle is correctly quoted as "prefer composition over inheritance". No one said you couldn't do both. Sometimes you have to do both. But given a choice, composition is usually the better one.

Your IResource reminds me of different patterns than the ones you mention. Parameter object makes constructing an object easier by bundling it's dependencies together.

Beware, taken to an extreme this smacks of a service locator which can be bad in some situations.

Respecting the Law of Demeter is a good thing if you understand it well. It is causing you a problem here but it's a good problem. It's forcing you to simplify access to health and mana until it's obvious that your Character isn't doing anything but aggregation.

What's missing is abstraction. Sure you promised Character would have more methods but as far as I see here Character isn't adding anything but unneeded indirection.

Right now Character looks like a brain dead value object (such as String). If that's what it's going to be then give it it's own copies of these values and flatten it out.

If Character is going to be a behavior object I'd expect Health to be hidden by encapsulation and interacted with using methods like Wound(int) and Die() not GetHealth(). This follows Tell, don't ask. A character's heath status is no one else's business. This is real encapsulation.

In either case the Character class should not be a brief stop on the way to dealing with character details. This should be THE place to resolve them. Don't make me dig past it.

7
  • Thank you very much @CandiedOrange. The Parameter object is exactly how I got into this situation without knowing about it, thank you. Character certainly is a behavior object with methods like Attack, but thank you for clarifying that Encapsulation is my issue, not Law of Demeter, Wound and such certainly belong on Character and Character should probably only provide readonly information such as CurrentHealth without giving access to the full Health object. Commented Apr 18, 2017 at 10:39
  • @ChrisWohlert most welcome. The issue isn't "read only". That would still be a getter. Heath is state and exposed state tempts people to do work on it outside of the object. That turns the object inside out. But presumably you have to report health to something. If that's say a view (GUI?) then the best way to follow tell, don't ask is to pass a (health focused?) view into Character and tell that view what % the health is at. That preserves encapsulation. Also lets you update as soon as health changes. Commented Apr 18, 2017 at 10:52
  • I'm sorry, by readonly I should've said immutable. Preventing others from working on it outside was the problem I tried to prevent with that sentence. The passing of a view object to the Character is very interesting, not something I would normally do. Would you prefer this to say a HealthChanged event? Which is how I would normally solve that issue. Commented Apr 18, 2017 at 14:39
  • Passing a view in and calling it on a change IS an event. Look up the observer pattern. It will show you how to do this for multiple views. Long as you pass the view all it needs then it doesn't need to call you back demanding you have getters. You don't even have to pass the real health. Just enough to display it for this view. Say a percentage. This would make Character a behavior object and mutable. If it has an identity that is not tied to it's state then it's an entity. Immutable won't let you even change heath without creating another object. Getters are for value objects like Strings. Commented Apr 18, 2017 at 21:36
  • I know an immutable Health will not let me change it without creating a new, which is exactly what I was thinking, such that Wound would say this.Health = this.Health.Subtract(damage);. I would be familiar with your approach in other languages, but since events are the observer pattern in C#, I probably just got it mixed up. The Character is already mutable and a behavior object if it has methods that change internal state, no? - I would only be using one of the solutions, either events or getters. Commented Apr 19, 2017 at 6:16
4

What benefits are you getting from bundling health and mana together? Those just sound like values to me and separate attributes, but regardless whether they are values or objects you could put them as properties instead. These are meant to be easily checked against the character.

I think you had it right the first time. If your mana/health might have behaviors or rules giving cause to be more than just a value, I think you should program against their interface (which allows you to mock them when unit testing Character's behaviors):

interface ICharacter
{
    IMana Mana { get; }
    IHealth Health { get; }
}

public class Character : ICharacter
{
    public IMana Mana { get; }
    public IHealth Health { get };

    public Character(IMana mana, IHealth health)
    {
        Mana = mana;
        Health = health;
    }
}

If they are just values, just have them be values. With the value approach you might not need to even to provide them to the constructor. You can just use reasonable defaults. Now where encapsulation becomes useful is you can bake-in the healing and mana logic within a publicly exposed method and the calling code cannot modify the health and mana without using the exposed methods:

interface ICharacter
{
    int Mana { get; }
    int Health { get; }
    void Heal(int numPotions);
    void RejuvenateMana(int numPotions);
}

public class Character : ICharacter
{
    public int Mana { get; private set; } // default is 0
    public int Health { get; private set; } = 100;

    public void Heal(int numPotions) 
    {
        Health += numPotions;//todo: add real logic
    }

    public void RejuvenateMana(int numPotions)
    {
        Mana += numPotions;//todo: add real logic
    }

}

Once you realize that you might have different behaviors and rules, you'll likely want to add in those rules as dependencies or have some other way to vary the behaviors between character types. Depending on how everything works together you might find that healing, rejuvenating, taking damage, etc might be handled by a different object and in that case you'd want to make health/mana be publicly assignable properties if ICharacter will be acted upon by something else. Otherwise it might be sensible to provide the dependencies that calculate health/mana in as a dependency.

Would you consider this good a idea over just having a property to IResource? - Why? / why not?

These seem to me to be 2 separate attributes of character. I think combining them would be doing so just for the sake of orgranizing things, and would cause calling code to have to unnecessarily dig for information that could have been readily available.

Is this pattern / antipattern of implementing the same interface that a class is composed of recognized, and if so, what is it called?

I'd call this over-engineering and over-generalization. IResource has become such a generic thing in this case it doesn't really have a good single meaning and breaks Interface Segregation principle in my opinion by being too generalized and not broken apart enough. What you are doing though by implementing an interface and taking in dependencies that implement that same interface is common though in some circumstances, in some programming languages all objects inherit from some kind of Object or in the case of Objective-C there is an NSObject class all inherit from and an NSObject protocol (interface). This pattern has been used before to bake things in for everything to have but usually only works in cases where Everything will need to have the same exact properties (ie: interface components will always have x,y positions, etc).

Any situations to be wary off, where this is a definitive no-go?

As I mentioned before I feel like this breaks ISP. Clients should not have to depend on things they don't need. If character is a resource then a character can't change independently from IResource since ICharacter inherits everything in the IResource interface. And ICharacter could potentially have IResource traits it doesn't need if IResource is used in such a generic manner and more traits get added that do not belong to ICharacter.


Edit: I'd really like to see how the Character class will interact with other classes. For instance if there was a BattleCalculator class that takes in 2 characters and looks at their attributes to see how much damage will be applied based on attributes like Health, Agility, Weapon, etc it might be the case that it doesn't need to know about mana (assuming mana is just being used to change other character attributes). In that case you can further split the interfaces so mana-related stuff is in a different interface, and the battle calculator doesn't need to know about it, and this assumes all characters would have Mana:

public interface IManaBearer 
{ 
    IMana Mana { get; } 
}
public interface ICharacter { ... }
public class Character: IManaBearer, ICharacter {...}

public class CharacterBattleCalculator
{
    public CharacterBattleCalculator(ICharacter player1, ICharacter player2)
    {
        ...
    }
    ...
}
2
  • 1
    Adding on to the points you've made here, with an example, a destructible chest will have health, but mana makes NO sense for it. This is why we have the interface segregation principal :D Commented Apr 12, 2017 at 20:43
  • 1
    Obviously, methods like Heal would be on Health, making it not a value object. Commented Apr 18, 2017 at 10:29
3

Is this pattern / antipattern of implementing the same interface that a class is composed of recognized, and if so, what is it called?

It's a Proxy or Dectorator. Proxies generally refer to Wrappers or Adapters that simply forward method calls onto another class or instance — like an internal property. And Decorators are basically Proxies that come with additional methods or "overrides."

Would you consider this good a idea over just having a property to IResource? - Why? / why not?

In and of itself, it's a neutral idea. It comes down to the nomenclature. If an ICharacter is an IResource, then it's a good idea. If it only has an IResource, it's a terrible idea.

Any situations to be wary off, where this is a definitive no-go?

In addition to when it's not a semantic fit, it's also a bad idea when the wrapping will be hard to maintain. This could be the case if the inner interface is volatile (still in development). ... I'd personally also avoid a proxy/decorator if the "principle of least knowledge" is my only justification — especially for large interfaces.

Composition over Inheritance, why not both?

In your case, because you're not actually doing both!

Classes are inherited. Interfaces are implemented. So, you're doing "both composition and implementing interfaces." And, that's a perfectly normal, everyday thing to do.

This is what "both" composition and inheritance would look like:

class A : B
{
  public C Prop;
}

Class A inherits from B and is composed of C.

So, generally speaking, why not do both?

No reason at all. If it makes sense for A to inherit from B and use C in its composition, do it. If not, don't.

Just do what makes sense.


Bonus advice time! For yours and your coworkers' sakes, be aware of why the principles exist. Preferring composition over inheritance has both benefits and drawbacks. And frankly, the advantages of Principle of Least Knowledge are shaky at best (in my opinion). But primarily, if C from our example can do things we don't want consumers of A to do directly, C should be private. But, if we're creating a wrapper for each method on C, we should just make C public.

19
  • Although "interfaces are implemented", abstractly they are identical to base classes, and that is why they are not present in many object oriented languages (they are not needed). So multiple interface implementation is a type of multiple inheritance, usually the only one allowed (otherwise, we have no need for interfaces). Commented Apr 13, 2017 at 22:55
  • @FrankHileman I'm really not sure what you're trying to say! But, I very much disagree that interfaces are "identical to base classes." When you implementing an interface, you're explicitly not inheriting anything, as you do from a base class. You're agreeing to fulfill a contract. Whereas, when you inherit from a base class, you're literally taking another class, along with its full implementation and all of it's contracts, as a "starting point."
    – svidgen
    Commented Apr 14, 2017 at 13:43
  • An interface, in a language such as C# or Java, is functionally identical to a purely abstract base class: one with no members implemented. Interfaces use inheritance exactly the same way as classes. The concept of interface was added to these languages only to work around a flaw in the language design: the inability to do multiple inheritance with classes. It was thought this would reduce complexity, but at the time, design issues with multiple inheritance were already solved. Interfaces should only be used when you need multiple inheritance. Commented Apr 14, 2017 at 13:55
  • An interface by itself is not a contract, no more than the abstract members in a base class. A contract specifies semantics using pre-conditions, post-conditions, and invariants. An interface is simply a collection of member signatures with no meaning. If you add some documentation to an interface, and someone reads it, you can at least create an informal contract. Commented Apr 14, 2017 at 13:57
  • @FrankHileman Regarding C# -- no. Abstract classes can contain implementation details. Not sure about Java. But yes ... that's what we mean by "contract." We mean, "this class has these public methods and properties."
    – svidgen
    Commented Apr 14, 2017 at 14:02
0

Two notes to keep you going:

  1. If someone knows ICharacter then it knows Iresource, so exposing the internals of the resource class didn't made the class using the character know less.

  2. I think you made it more confusing that someone knows this interface of IResource, which was made because you said that this two pieces of data comes together, and then you allow it to access each piece of data individually. You need to decide - either both pieces come together (and then they are also exposed together), or that it makes since to have each of them without the other (and then don't have them make a class)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.