Search code examples
c#xnamonogamecomposition

Reuse similar constructors without the use of inheritance


This is a code for MonoGame 3.8.1 and .NET 6.

public interface IEntity
{
    int Size { get; }
    Vector2 Position { get; }
}
public class Player : IEntity
{
    public int Size { get; } = 32;
    public Vector2 Position { get; private set; }

    public Player(Scene scene)
    {
        var spawnOffset = new Vector2(0, -3);

        Position = new Vector2(
            spawnOffset.X * scene.TileSize + scene.Room.Center.x - Size / 2,
            spawnOffset.Y * scene.TileSize + scene.Room.Center.y - Size / 2);
    }
}
public class Enemy : IEntity
{
    public int Size { get; } = 32;
    public Vector2 Position { get; private set; }

    public Enemy(Scene scene)
    {
        var spawnOffset = new Vector2(0, 0);
    
        Position = new Vector2(
            spawnOffset.X * scene.TileSize + scene.Room.Center.x - Size / 2,
            spawnOffset.Y * scene.TileSize + scene.Room.Center.y - Size / 2);
    }

}

Without the use of inheritance, I want every class that implements IEntity to be able to reuse calculations for Position assignment. The only difference between both constructors is the spawnOffset values.

What's the most simple way to do this?

Normally - I would call the base class constructor, but here I'm trying to do this without a base class.


Solution

  • Looks like you follow "prefer composition over inheritance" - indeed that is a valid approach, just finish that by extracting "position" functionality into separate class:

    
    class EntityPosition
    {
        public Vector2 Position { get; private set; }
        public EntityPosition (Scene scene, Vector2 spawnOffset, int size)
        {
           Position = new Vector2(
            spawnOffset.X * scene.TileSize + scene.Room.Center.x - size / 2,
            spawnOffset.Y * scene.TileSize + scene.Room.Center.y - size / 2);
        }
        // add other shared methods for position updates here as necessary
    }
    
    public class Player : IEntity
    {
        EntityPosition position;
        public int Size { get; } = 32;
        public Vector2 Position => position.Position;
    
        public Player(Scene scene)
        {
            var spawnOffset = new Vector2(0, -3);
    
            position = EntityPosition(scene, spawnOffset, Size);
        }
    }