Inheritance and composition are two fundamental concepts in object-oriented programming (OOP), but they are used differently and have different purposes. The objective of this post is to review those purposes, and some things to keep in mind when choosing them.
When we think about applying inheritance in our designs, we have to understand:
On the other hand, if we think about composing objects together:
The question of whether composition is better than inheritance or vice versa is a debated topic in software design. Both approaches have their advantages and disadvantages, and the choice depends on the specific project context and requirements. Here I will present you with an example where composition can be preferable to inheritance.
Let's explore an example in Java that illustrates how composition can be preferable to inheritance in certain cases. Suppose we are working on an order processing system in an online store.
First, let's consider an approach using inheritance to represent different types of purchasable products, such as books and electronics:
// Clase base para productos class Producto { String nombre; double precio; Producto(String nombre, double precio) { this.nombre = nombre; this.precio = precio; } void procesarPedido() { System.out.println("Procesando pedido para " nombre); } } // Clase para productos electrónicos que hereda de Producto class ProductoElectronico extends Producto { String modelo; ProductoElectronico(String nombre, double precio, String modelo) { super(nombre, precio); this.modelo = modelo; } } // Clase para libros que hereda de Producto class Libro extends Producto { String autor; Libro(String nombre, double precio, String autor) { super(nombre, precio); this.autor = autor; } }
This approach works, but what if you need to introduce new product types or add specific functionality for certain product types?
Instead of relying entirely on inheritance, we could use composition to handle different types of products more flexibly:
// Clase para productos class Producto { String nombre; double precio; Producto(String nombre, double precio) { this.nombre = nombre; this.precio = precio; } void procesarPedido() { System.out.println("Procesando pedido para " nombre); } } // Clase para productos electrónicos que utiliza composición class ProductoElectronico { Producto producto; String modelo; ProductoElectronico(String nombre, double precio, String modelo) { this.producto = new Producto(nombre, precio); this.modelo = modelo; } // Puedes agregar lógica específica para productos electrónicos si es necesario void procesarPedidoEspecifico() { System.out.println("Procesando pedido específico para " producto.nombre); } } // Clase para libros que utiliza composición class Libro { Producto producto; String autor; Libro(String nombre, double precio, String autor) { this.producto = new Producto(nombre, precio); this.autor = autor; } // Puedes agregar lógica específica para libros si es necesario void procesarPedidoEspecifico() { System.out.println("Procesando pedido específico para " producto.nombre); } }
In this approach, each product type has an instance of the Product class, allowing common logic to be shared for processing orders. Additionally, each product type can have its own specific logic using methods such as processSpecificOrder(). This design is more flexible and makes it easier to introduce new product types or modify type-specific logic without affecting the inheritance hierarchy.
While the choice between inheritance and composition in software design depends on the context and specific requirements of the problem you are addressing. Here are some situations where you might consider inheritance as a more appropriate option than composition:
class Vehiculo { // ... } class Automovil extends Vehiculo { // ... }
class Animal { void comer() { // Lógica común para comer } } class Perro extends Animal { void ladrar() { // Lógica específica para ladrar } }
class Figura { void dibujar() { // Lógica común para dibujar una figura } } class Circulo extends Figura { void dibujar() { // Lógica específica para dibujar un círculo } } class Cuadrado extends Figura { void dibujar() { // Lógica específica para dibujar un cuadrado } }
If we continue to evaluate the pros and cons of inheritance, one of the problems that can arise from bad inheritance is that we would violate the Interface Segregation Principle, which states that clients should not be forced to depend on interfaces that they do not use. If an interface is extended in a way that includes methods that are not relevant to all implementations, clients using that interface could be forced to implement or depend on methods they do not need, which can lead to a less clean and more difficult design. to maintain.
In summary, inheritance focuses on the "is a" relationship and is used to model class hierarchies, while composition focuses on the "has a" relationship and is used to construct complex objects from others. simpler objects. Both approaches have their specific use cases and are chosen based on the structure and nature of the relationships in the software design.
Disclaimer: All resources provided are partly from the Internet. If there is any infringement of your copyright or other rights and interests, please explain the detailed reasons and provide proof of copyright or rights and interests and then send it to the email: [email protected] We will handle it for you as soon as possible.
Copyright© 2022 湘ICP备2022001581号-3