Just Learn Code

Understanding Inheritance and Composition in Object-Oriented Programming

Inheritance and

Composition in Object-Oriented Programming

In the world of object-oriented programming (OOP), there are several concepts that are fundamental to understanding how to design and implement a program. Two such concepts are inheritance and composition.

Both are used to establish relationships between classes, but they differ in how they accomplish this goal. In this article, we will define these concepts, provide examples, and explain how they can be used to improve code reusability, flexibility, and scalability.

Inheritance and composition are related but distinct concepts in OOP. Both are used to define relationships between classes, but the particulars of those relationships differ.

Understanding the differences between them is essential to designing effective class hierarchies that can be reused in different contexts and that are flexible enough to accommodate future changes.

Inheritance

Inheritance is a type of relationship in which one class, called the parent class or superclass, provides its attributes and methods to one or more subclasses. The subclasses, also known as child classes or derived classes, inherit these attributes and methods and can add their own as well.

The keyword ‘extends’ is used in Java to specify inheritance. An IS-A relationship exists between a parent class and the subclass that inherits from it.

That is, the subclass is a specialized instance of the parent class. For example, a dog is an animal, and a German shepherd is a dog.

Therefore, a German shepherd IS-A dog, and by extension, IS-A animal. Here’s some sample code in Java that demonstrates inheritance between an Animal class and a Dog class:

“`

class Animal {

public void whatAmI() {

System.out.println(“I am an animal”);

}

}

class Dog extends Animal {

public void whatAmI() {

System.out.println(“I am a dog”);

}

}

Dog myDog = new Dog();

myDog.whatAmI(); // Output: “I am a dog”

“`

In this example, the Animal class provides a method called `whatAmI()` that simply prints “I am an animal”.

The Dog class extends the Animal class, which means it inherits `whatAmI()`. However, it overrides the method to print “I am a dog” instead.

When we create a new Dog object and call `whatAmI()`, the output is “I am a dog”.

Composition

Composition is another type of relationship in which one class is composed of one or more objects of another class. The class that contains the objects is called the parent class or container class, while the classes that are held by the container class are called the child classes or component classes.

A HAS-A relationship exists between the parent class and its components. That is, the parent class HAS-A reference to one or more objects of the child classes.

For example, a dog HAS-A set of legs. Therefore, we can say that the Legs class is a component of the Dog class.

Here’s some sample code in Java that demonstrates composition between a Legs class and a Dog class:

“`

class Legs {

private int numLegs;

public Legs(int numLegs) {

this.numLegs = numLegs;

}

public int howManyLegs() {

return this.numLegs;

}

}

class Dog {

private Legs legs;

public Dog(int numLegs) {

this.legs = new Legs(numLegs);

}

public int getNumLegs() {

return this.legs.howManyLegs();

}

}

Dog myDog = new Dog(4);

myDog.getNumLegs(); // Output: 4

“`

In this example, the Legs class has a private field `numLegs` that is set by its constructor. It also has a method called `howManyLegs()` that returns `numLegs`.

The Dog class has a private field `legs` that refers to an instance of the Legs class. It also has a method called `getNumLegs()` that calls `howManyLegs()` on the `legs` instance variable.

When we create a new Dog object with 4 legs and call `getNumLegs()`, the output is 4. In summary, composition is a way of combining several different objects into a single composite object, while inheritance is a way of defining a hierarchy of related classes.

Both mechanisms can be used to establish relationships between classes and improve code reusability, flexibility, and scalability. Knowing when to use composition versus inheritance is an essential part of designing effective and efficient class hierarchies.

In object-oriented programming (OOP), there are two fundamental ways to establish relationships between classes: IS-A relationship and HAS-A relationship. Understanding the differences between these two relationships is crucial to designing effective class hierarchies and creating reusable, scalable code.

In this article, we will detail the key differences between IS-A relationship and HAS-A relationship, and provide examples to illustrate these distinctions.

IS-A Relationship

An IS-A relationship exists between two classes when one class is a type of the other class. For example, a dog is a type of animal, so we can say that the Dog class is a subclass of the Animal class.

The subclass, or child class, inherits attributes and methods from the superclass, or parent class, and may also add new attributes and methods of its own. The primary mechanism for establishing an IS-A relationship is inheritance, where the child class extends the parent class.

Java, for instance, uses the ‘extends’ keyword to specify this relationship. The subclass has access to all of the attributes and methods of the parent class, as well as those it creates on its own.

However, the reverse is not true the parent class does not have access to the attributes and methods of the child class. One key difference between the IS-A relationship and the HAS-A relationship is the way in which the two classes interact.

In the IS-A relationship, the two classes work together as part of a hierarchy. The child class may be more specific than the parent class, and therefore have additional attributes and methods, but it still shares some attributes and methods with the parent class.

Here’s another example in Java to illustrate the IS-A relationship between a Bird superclass and a Duck subclass:

“`

class Bird {

private String birdType;

public Bird(String birdType) {

this.birdType = birdType;

}

public void fly() {

System.out.println(birdType + ” is flying”);

}

}

class Duck extends Bird {

public Duck() {

super(“Duck”);

}

public void quack() {

System.out.println(“Quack!”);

}

}

Duck myDuck = new Duck();

myDuck.fly(); // Output: “Duck is flying”

“`

In this example, the Bird class has a private field `birdType` and a method `fly()` that prints the bird type followed by “is flying”. The Duck class extends the Bird class and adds a method `quack()`.

When we create a new Duck object and call `fly()`, the output is “Duck is flying”. This demonstrates that the Duck class shares a method with its parent class and adds methods of its own.

HAS-A Relationship

A HAS-A relationship exists between two classes when one class contains an instance of another class, rather than when one class is a type of another class. For example, a car has an engine, so we can say that the Car class has an instance of the Engine class.

The parent class, or container class, holds a reference to one or more objects of the child class, or component class. The primary mechanism for establishing a HAS-A relationship is composition, where the parent class creates an instance of the child class as an attribute.

Java, for example, allows you to create an instance of a class as a member variable of another class.

One key difference between the HAS-A relationship and the IS-A relationship is the way in which the two classes interact.

In the HAS-A relationship, the parent class contains an instance of the child class and can call its methods, but the child class cannot call the methods of the parent class. A HAS-A relationship is typically useful when we want to reuse code by encapsulating certain functions in a separate class.

Here’s another example in Java to demonstrate the HAS-A relationship between a House class and a Room class:

“`

class Room {

private String roomType;

public Room(String roomType) {

this.roomType = roomType;

}

public void enter() {

System.out.println(“You are entering a ” + roomType);

}

}

class House {

private Room livingRoom;

private Room kitchen;

public House() {

livingRoom = new Room(“living room”);

kitchen = new Room(“kitchen”);

}

public void enterLivingRoom() {

livingRoom.enter();

}

public void enterKitchen() {

kitchen.enter();

}

}

House myHouse = new House();

myHouse.enterLivingRoom(); // Output: “You are entering a living room”

“`

In this example, the Room class has a private field `roomType` and a method `enter()` that prints “You are entering a ” followed by the room type. The House class has two private fields, `livingRoom` and `kitchen`, that are instantiated as Room objects in the constructor.

The House class also has two methods, `enterLivingRoom()` and `enterKitchen()`, that call the `enter()` method on the appropriate Room object. When we create a new House object and call `enterLivingRoom()`, the output is “You are entering a living room”.

Conclusion

In summary, the key differences between IS-A relationship and HAS-A relationship lie in the type of relationship established between the two classes and the way in which they interact with each other. The IS-A relationship is a hierarchical relationship, where a child class is a type of its parent class, while the HAS-A relationship is a containment relationship, where a parent class holds an instance of a child class.

Both types of relationships are fundamental to designing effective and efficient class hierarchies and creating reusable, scalable code. In conclusion, the key differences between IS-A relationship and HAS-A relationship in object-oriented programming are fundamental to designing scalable, reusable class hierarchies.

Establishing these relationships relies on inheritance and composition, respectively, with each relationship serving a different purpose. The IS-A relationship creates a hierarchy between classes where a child class is a type of its parent class, while the HAS-A relationship involves a parent class holding an instance of a child class.

Understanding these fundamental concepts is crucial in designing effective and efficient class hierarchies. By doing so, developers can create code that is flexible, reusable, and scalable.

Popular Posts