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)
{
...
}
...
}