-5

I have read many articles and answers on the internet, all of which say where Composition must be used or why Composition must be preferred over Inheritance. But that is not my question!

What is the main purpose of Composition? For those who say Code reuse. I have another question. When inheritance is there to serve the purpose of code reuse, why use Composition?

One thing I want to know is that if Some "Y" functionality is also serving the same purpose, then why should I use "X". There should be a purpose which is only served by "X", and not by any other "Y".

So, my question is what is that purpose in this case of Composition(X) & Inheritance(Y)?

I am new in the field, and it would really help if someone answered my question.

Villat
  • 1,455
  • 1
  • 16
  • 33
  • 1
    If you are asking about `C#`, why did you also tag `Java`? – Nexevis Oct 04 '19 at 13:52
  • Well for one thing, _composition_ is a means to getting around the _[restriction of multiple inheritence in C#](https://stackoverflow.com/a/178368/585968)_. The net result is arguably the same –  Oct 04 '19 at 13:59

2 Answers2

1

From personal experience,

Use of Inheritance

The use of inheritance is when a function requires something from a object and multiple objects have that something, basically, say we have these 3 classes:

//This is the base class, the one from which others inherit
abstract class WaitableObject
{
     protected WaitableObject(IntPtr handle) { Handle  = handle; }

     public IntPtr Handle { get; }
}

//Inherits from WaitableObject
class Object1 : WaitableObject
{
    public Object1() : base(new IntPtr(1))
    {
    }

    void DoSomething();
}

class Object2 : WaitableObject
{
    public Object2() : base(new IntPtr(2))
    {
    }

    int CalculateSomething(int a, int b);
}

and then we have a method which can wait on a object using the object's Handle e.g.

bool WaitOn(WaitableObject obj)
{
   // do something with obj.Handle
}

So, instead of creating 2 methods, one which accepts Object1 and another which accepts Object2, we made both of those classes inherit from the same base class sins they both has something in common, aka Handle. Same applies to interface inheritance.

Use of Composition

A use of composition is to have a type manage other types so those types don't get accidentally accessed when the main type is destroyed. A good example of this is Unity Engine's GameObject class. You can add to a game object components which are separate things but, when the main object is destroyed so are all of it's components, so incase of a class holding onto a destroyed game object's component tries to access it, it will be hit with a null exception sins that component has no meaning as the game object to which it was once attached to was destroyed. Basically, it's so parts of a type, which should only be allowed access to if the main type is alive, don't stay alive after the main type is destroyed, that's AFAIK the main use of composition.

A example which isn't 3rd party would be System.Windows.Forms.Form class, same principle with the components and same thing with the destruction.

Use of Polymorphism [Read Edit Note]

Polymorphism is mainly used when multiple classes/structures can use the same thing, like System.IO's BinaryReader & BinaryWriter, both of them can use the same stream and there is no need to open 2 separate, e.g.

public void AppendLastByte(string filename)
{
   // opens a Stream of the specified file with read & write rights
   Stream myFileStream = File.Open(filename, FileMode.Open, FileAccess.ReadWrite);

   myFileStream = (myFileStream.Length - 1); //set the position to the last byte.

   //Created a binary reader, so we can read the data of the stream.
   var reader = new BinaryReader(myFileStream);

   //Created a binary write, so we can write data to the stream.
   var writer = new BinaryWriter(newFileStream);

   //
   //Note that when a read/write operation is done the position in the underline stream is moved by the amount of bytes read/written.
   //

  //Read the last byte of the stream, as written above, the underline stream's position is now "myFileStream.Length", sins it was "myFileStream.Length - 1"
  byte lastByte = reader.ReadByte();

  //Wrote the read byte to the end of the file, aka appended it.
  writer.Write(lastByte);

  //disposal
  myFileStream.Close();
}

So, instead of managing 2 streams, and consuming more resources, we just used 1. Another possibility of using polymorphism is to limit the amount of stuff that can be done to the underline objects. Lets take the same 3 things, Stream, BinaryReader & BinaryWriter, sins Stream does have the ability to read and write, BinaryReader makes it so the stream is kind of limited to only reading and vise versa for BinaryWriter.

Vincent Bree
  • 425
  • 4
  • 10
  • @MickyD Now that you mention it, yes I did. What was composition again, guess I forgot? – Vincent Bree Oct 05 '19 at 18:56
  • @MickyD Thanks for linking me that, still a bit confused about what exactly composition is, but I updated the answer, let me know if the new stuff is correct or not. Hope it is. PS: Left the polymorphism part in just incase, maybe it could be of some help to someone that reads it. – Vincent Bree Oct 06 '19 at 01:03
  • That's it, thanks for the update +1. You've gotten the essence. It relates (pun not intended) to another form of association called _aggregation_. To learn more about the two check out https://en.wikipedia.org/wiki/Object_composition. Basically they are similar, the major difference being in aggregation, the part objects can exist even when the other is deleted. –  Oct 06 '19 at 02:35
0

I hope I'm understanding your question as I'm also new to this so please note I'm a complete beginner when reading the below :)

If I have animals Dog, Cat and Crocodile that inherit from Animal, I might decide that I want dogs to "bark" and cats to "meow".

So I add an abstract MakeNoise() to my Animal class and start implementing concrete implementations, only to find that I don't really want to implement a MakeNoise() for my crocodile, because in my scenario the crocodile is silent.

abstract public class Animal
{
    abstract public string GetNameAsString();
    abstract public void MakeNoise();
}

public class Cat : Animal
{
    public override string GetNameAsString() => "cat";
    public override void MakeNoise() => Console.WriteLine("meow");
}

public class Dog : Animal
{

    public override string GetNameAsString() => "dog";
    public override void MakeNoise() => Console.WriteLine("woof");
}

public class Crocodile : Animal
{
    public override string GetNameAsString() => "croc";

    // I don't want croc to make a noise, but I have to implement it anyway,
    // else the compiler will complain about the missing implementation
    public override void MakeNoise() => Console.WriteLine("what here?");
}

I may have been better off not adding MakeNoise() to my Animal class, instead I could have used composition and created a separate IAnimalNoise interface and used this for the dog and cat, but not the crocodile.

abstract public class Animal
{
    abstract public string GetNameAsString();
}

interface IAnimalNoise
{
    abstract public void MakeNoise();
}

public class Cat : Animal, IAnimalNoise
{
    public override string GetNameAsString() => "cat";
    public void MakeNoise() => Console.WriteLine("meow");
}

public class Dog : Animal, IAnimalNoise
{

    public override string GetNameAsString() => "dog";
    public void MakeNoise() => Console.WriteLine("woof");
}

public class Crocodile : Animal
{
    public override string GetNameAsString() => "croc";

    // Now we simply omit the interface and don't need to implement the method
}

For a better explanation or further reading, SOLID principles and Liskov substitution might be a good place to look...

drkmtr
  • 164
  • 1
  • 6
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/200577/discussion-between-drkmtr-and-mickyd). – drkmtr Oct 08 '19 at 20:32