Search code examples
c#composition

Understanding composition in C#


I wanted to gain a better understanding of composition over inheritance. I watched a few tutorials which explain the concepts very well but using languages I am more familiar with such as Python. However, I am learning C# at the moment and am struggling to implement what I have learned on the subject and wondered if anyone could help. Here is the code I have:

using System;

namespace Composition
{
    class Program
    {
        static void Main(string[] args)
        {
            SuperBot steven = new SuperBot(new Dog(),new Robot());
            steven.Bark();


        }
    }

    class Dog
    {
        public void Bark()
        {
            Console.WriteLine("Woof");
        }

    }

    class Robot
    {
        public void Move()
        {
            Console.WriteLine("I'm moving!");
        }
    }

    class CleanRobot
    {
        public void Clean()
        {
            Console.WriteLine("Just keep dusting, just keep dusting");
        }
    }

    class SuperBot
    {
        // can clean, move and bark
        public Dog o1;
        public Robot o2;
        public CleanRobot o3;

        public SuperBot(Dog dog, Robot robot)
        {
            this.o1 = dog;
            this.o2 = robot;

        }

    }

}

Essentially, I have a Dog that can bark, a Robot that can move and a CleanRobot that can clean. I want to create a SuperBot that can move, bark and clean, and use composition to achieve this.

I have two main questions:

  1. The above is what I have coded so far, but yet it will not allow me to call the Bark method on my SuperBot object, as it says SuperBot class doesn't contain this method.

  2. How would I use composition in the case where my Dog class could also Eat() but I do not want to use this method for my SuperBot class?

Really appreciate any help - struggling to get my head around this!

UPDATE - ATTEMPT USING INTERFACES

using System;

namespace Composition
{
    public interface ICanBark
    {
        string Bark();
    }

    public interface ICanMove
    {
        string Move();
    }

    public interface ICanClean
    {
        string Clean();
    }

    class Program
    {


    static void Main(string[] args)
        {
            SuperBot steven = new SuperBot();
            steven.Bark();

        }
    }

    class Dog : ICanBark 
    {
        public string Bark()
        {
            return "Woof"; 
        }
    }

    class Robot : ICanMove
    {
        public string Move()
        {
           return "I'm moving";
        }
    }

    class CleanRobot : ICanClean
    {
        public string Clean()
        {
           return "Just keep dusting, just keep dusting";
        }
    }

    class SuperBot : ICanBark, ICanMove, ICanClean
    { 
        public string Bark()
        {
            return "Barking";
        }
    }

}

Solution

  • When using composition as in your example, you unfortunately have to implement the exposed methods in the composing class as well:

    class SuperBot
    {
        // can clean, move and bark
        public Dog o1;
        public Robot o2;
        public CleanRobot o3;
    
        public SuperBot(Dog dog, Robot robot, CleanRobot cleanRobot)
        {
            this.o1 = dog;
            this.o2 = robot;
            this.o3 = cleanRobot;
        }
    
        public void Bark() => o1.Bark();
        public void Move() => o2.Move();
        public void Clean() => o3.Clean();
    }
    

    This will solve your compiler error. Also if you add more methods to Dog, Robot or CleanRobot, they will not impact what the SuperBot offers, i.e. if Dog has a method Eat(), SuperBot will not have this method unless you add it as well.

    Conceptually you use composition like this, if you model a SuperBot as actually consisting of a Dog, a Robot and a CleanRobot. The SuperBot then uses its Dog to bark and its CleanRobot to clean.


    Edit (from comments):

    If you want to have a function that calls Bark

        public void GoodBoy(Dog dog)
        {
            dog.Bark();
        }
    

    You cannot pass a SuperRobot to this method. In that case you need a common interface for Dog and SuperRobot that contains the Bark method.