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
Is this pattern / antipattern of implementing the same interface that a class is composed of recognized, and if so, what is it called?
Would you consider this good a idea over just having a property to IResource? - Why? / why not?
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.