c++oopdesign-patterns

Is Directory to SubDirectory more of a composition or inheritance?


In object-oriented programming, there are two main relationships between objects.

  1. Inheritance (is-a-relation)
  2. Composition (has-a-relation / also called containment)

For inheritance, one can have a relationship between different file types. Text files and bitmap files are files. Because of this, one could code

class File
{
public:
  void GetFileSize() { /* Implementation */ }
};
class BMPFile :public File {};
class TextFile:public File {};

By saying inheritance, the GetFileSize implementation in the base class (File) can be reused in derived classes BMPFile and TextFile. This is basic code reusability using inheritance.

For composition, one can have a relationship between a directory and files.

class Directory
{
  std::list<File> list_of_files;
}

Now comes the main part of my question.

a) What is the relationship between a directory and a sub-directory?

b) Since a directory contains a sub-directory, it is definitely a composition. Is my understanding correct?

c) Since a sub-directory has all the properties of a directory, it is also an inheritance. Is my understanding correct?

d) I believe a sub-directory has inheritance relationship with a directory because of the following analogy. Let us say I want to have a Directory class that has the following behaviour/properties

class Directory
{
public:
  virtual bool HasSubDirectory {/*Implementation code*/}
  virtual void CreateSubDirectory(std::string dirName){/*Implementation code*/}
  virtual void DeleteSubDirectory(){/*Implementation code*/}
  virtual std::list<SubDirectory> ListAllSubDirectories{/*Implementation code*/}
};
class SubDirectory : public Directory{}

By making a SubDirectory inheriting from Directory, I can achieve good code reusability. (I am also aware of code reusability through delegation in case of composition. But may be for this example inheritance is better I believe?)

e) There is a composition design pattern in Gang of Four, which is for a relationship between tree kind of a structure. Is the above example is a good candidate for composition design pattern ? I am changing the Directory class as this

class Directory
{
public:
  virtual bool HasSubDirectory =0;
  virtual void CreateSubDirectory(std::string dirName)=0;
  virtual void DeleteSubDirectory()=0;
  virtual std::list<Directory*> ListAllSubDirectories=0;
};
class SubDirectory : public Directory{
  public:
  virtual bool HasSubDirectory {/*Implementation code*/}
  virtual void CreateSubDirectory(std::string dirName){/*Implementation code*/}
  virtual void DeleteSubDirectory(){/*Implementation code*/}
  virtual std::list<Directory*> ListAllSubDirectories{/*Implementation code*/}
}

I can get example for inheritance/composition. But I want an example which contains both. Hence I wanted to know whether this is a good candidate.


Solution

  • Let's look at some example of Directory class (interface with abstract methods):

    class Directory {
        public:
        virtual std::list<Directory> subDirectories();
        virtual void dele();
        virtual void addDirectory(std::string withName);
    };
    
    1. Composition and inheritance are relationships between two classes, but as you can see in the code we don’t have a Subdirectory class, and therefore we can’t talk about the corresponding relationships.
    2. We will have implementations of the Directory interface (inheritance relationship), for example FileSystemDirectory, which will encapsulate its path in the file system (composition relationship), but this will be a composition between the Directory class and the class representing the path in the file system.
    3. By writing the method std::list<string> ListAllSubDirectories, you didn't actually use an object-oriented approach, you just returned a list of strings (not directories).

    Considering the edited part of the question. The Subdirectory type makes no sense, if it is an interface, it does not contain any additional methods, if it is a class, it will encapsulate the same as the base class and have the same behavior.