«Если рабочий хочет хорошо выполнять свою работу, он должен сначала заточить свои инструменты» — Конфуций, «Аналитики Конфуция. Лу Лингун»
титульная страница > программирование > Композиция против наследования

Композиция против наследования

Опубликовано 9 ноября 2024 г.
Просматривать:234

Composición vs Herencia

Введение

Наследование и композиция — две фундаментальные концепции объектно-ориентированного программирования (ООП), но они используются по-разному и имеют разные цели. Цель этой статьи — рассмотреть эти цели и некоторые моменты, которые следует учитывать при их выборе.

Концепции наследования

Когда мы думаем о применении наследования в наших проектах, мы должны понимать:

  • Определение: При наследовании класс (называемый производным классом или подклассом) может наследовать свойства и поведение от другого класса (называемого базовым классом или суперклассом). Производный класс может расширять или изменять функциональность базового класса.
  • Отношения: Это отношения «есть» (is-a). Например, если у вас есть класс «Транспортное средство» и другой класс «Автомобиль», класс «Автомобиль» является подклассом «Транспортное средство».
  • Преимущества: способствует повторному использованию кода и позволяет легко расширять функциональность.

Концепции композиции

С другой стороны, если мы подумаем о составлении объектов вместе:

  • Определение: В композиции объект содержит другие объекты и делегирует им часть своих функций. Вместо наследования класс использует экземпляры других классов для реализации своей функциональности.
  • Отношения: Это отношения типа «есть». Например, если у вас есть класс «Двигатель» и класс «Автомобиль», класс «Автомобиль» может иметь объект класса «Двигатель».
  • Преимущества: большая гибкость и меньшая связь между классами. Изменения в одном классе не влияют напрямую на другой.

Почему композиция по наследству?

Вопрос о том, лучше ли композиция, чем наследование или наоборот, является дискуссионной темой в разработке программного обеспечения. Оба подхода имеют свои преимущества и недостатки, и выбор зависит от конкретного контекста и требований проекта. Здесь я представлю вам пример, где композиция может быть предпочтительнее наследования.

Давайте рассмотрим пример на Java, который иллюстрирует, что в определенных случаях композиция может быть предпочтительнее наследования. Предположим, мы работаем над системой обработки заказов в интернет-магазине.

  • Подход к наследованию:

Во-первых, давайте рассмотрим подход, использующий наследование для представления различных типов покупаемых продуктов, таких как книги и электроника:

// 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;
    }
}

Этот подход работает, но что, если вам нужно представить новые типы продуктов или добавить конкретную функциональность для определенных типов продуктов?

  • Фокус с помощью композиции:

Вместо того чтобы полностью полагаться на наследование, мы могли бы использовать композицию для более гибкой обработки различных типов продуктов:

// 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);
    }
}

При таком подходе каждый тип продукта имеет экземпляр класса Product, что позволяет использовать общую логику для обработки заказов. Кроме того, каждый тип продукта может иметь свою собственную логику с использованием таких методов, какprocessSpecificOrder(). Такая конструкция более гибкая и упрощает внедрение новых типов продуктов или изменение логики, специфичной для типа, не затрагивая иерархию наследования.

Когда применять наследование?

Хотя выбор между наследованием и композицией при проектировании программного обеспечения зависит от контекста и конкретных требований решаемой проблемы. Вот несколько ситуаций, в которых наследование может оказаться более подходящим вариантом, чем композиция:

  • Отношения «есть»: Наследование особенно целесообразно, когда между классами существует четкая связь «есть». Если класс B является более конкретной или специализированной версией класса A, то наследование имеет смысл. Например, если у вас есть класс транспортного средства и класс автомобиля, связь «является-а» очевидна, поскольку автомобиль — это тип транспортного средства.
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
    }
}

  • Расширение функциональности: если вы расширяете или специализируете существующую функциональность, наследование может быть более естественным. Например, если вы разрабатываете библиотеку и предоставляете базовому классу базовую функциональность, пользователи вашей библиотеки могут наследовать этот базовый класс для расширения этой функциональности.

Что произойдет, если мы получим плохое наследство?

Если мы продолжим оценивать плюсы и минусы наследования, одна из проблем, которые могут возникнуть из-за плохого наследования, заключается в том, что мы нарушим принцип разделения интерфейсов, который гласит, что клиенты не должны быть вынуждены зависеть от интерфейсов, которые они используют. не использовать. Если интерфейс расширен таким образом, что включает в себя методы, которые не подходят для всех реализаций, клиенты, использующие этот интерфейс, могут быть вынуждены реализовывать или зависеть от методов, которые им не нужны, что может привести к менее чистому и более сложному проектированию. поддерживать.

Заключение

Подводя итог, наследование фокусируется на отношении «является» и используется для моделирования иерархии классов, тогда как композиция фокусируется на отношении «имеет» и используется для создания сложных объектов из других более простых объектов. Оба подхода имеют свои конкретные варианты использования и выбираются на основе структуры и характера отношений при разработке программного обеспечения.

Заявление о выпуске Эта статья воспроизведена по адресу: https://dev.to/rlgino/composicion-vs-herencia-4664?1. Если есть какие-либо нарушения, свяжитесь с [email protected], чтобы удалить ее.
Последний учебник Более>

Изучайте китайский

Отказ от ответственности: Все предоставленные ресурсы частично взяты из Интернета. В случае нарушения ваших авторских прав или других прав и интересов, пожалуйста, объясните подробные причины и предоставьте доказательства авторских прав или прав и интересов, а затем отправьте их по электронной почте: [email protected]. Мы сделаем это за вас как можно скорее.

Copyright© 2022 湘ICP备2022001581号-3