I've been refactoring my code and got to the point when my Unit has following interface:
public interface IUnit : Entity, IUpdatable
{
byte Team { get; }
bool CanHelp(IUnit unit);
bool CanHurt(IUnit unit);
Position Position { get; }
void CastSpell(ISpell spell, IUnit target);
void GiveSpell(ISpell spell);
void RemoveSpell(ISpell spell);
Duration GetCooldown(ISpell spell);
void SetCooldown(ISpell spell, Duration cooldown);
bool Alive { get; }
float CurrentHealth { get; }
float MaxHealth { get; }
void TakeDamage(HealthChangeEvent @event);
void Heal(HealthChangeEvent @event);
void ApplyStatus(EffectApplicationData data, Aura arua, long duration);
void RemoveStatus(SpellId aura);
bool HasStatus(SpellId aura);
bool CanPay(AbilityCost cost);
bool HasResource(ResourceType type);
float GetResourceValue(ResourceType type);
void GiveResource(ResourceType type, float value);
void SpendResource(AbilityCost cost);
Vector3 GetMovement();
}
The most troubling part is IUnit
used as target to apply all of ISpell
/IAura
effects, so whenever I want to add some functionality, i have to add new functions to object, that is already too thick.
I have no idea what to do except use IUnit
as container for IAuraOwner
, IHealthOwner
etc. and use component system with IUnit.GetComponent<T>();
or direct getters IUnit.Health
/IUnit.Auras
.
What are good/common practices to handle this dependencies?
It's difficult to recommend the most suitable solution to you since I can't investigate the project's source code. But the code you have shown violates the Interface Separation Principle, ISP (SOLID).
To fix this, you should start by defining individual responsibilities and creating separate interfaces for each, implementing only those interfaces that match their functionality.
Please consider using the Command, Decorator, or Strategy patterns (GoF). Also pay attention to the use of the Repository pattern with Services Layer.