”工欲善其事,必先利其器。“—孔子《论语.录灵公》
首页 > 编程 > 组合与继承

组合与继承

发布于2024-11-09
浏览:443

Composición vs Herencia

介绍

继承和组合是面向对象编程(OOP)中的两个基本概念,但它们的用法不同并且具有不同的目的。这篇文章的目的是回顾这些目的,以及选择它们时要记住的一些事情。

继承的概念

当我们考虑在设计中应用继承时,我们必须了解:

  • 定义:在继承中,一个类(称为派生类或子类)可以从另一个类(称为基类或超类)继承属性和行为。派生类可以扩展或修改基类的功能。
  • Relationship:是一个关系“is a”(is-a)。例如,如果您有一个类“Vehicle”和另一个类“Car”,则类“Car”是“Vehicle”的子类。
  • 优点:促进代码重用并允许轻松扩展功能。

构图概念

另一方面,如果我们考虑将对象组合在一起:

  • 定义:在组合中,一个对象包含其他对象并将其部分功能委托给它们。类不使用继承,而是使用其他类的实例来实现其功能。
  • 关系:这是一种“has-a”关系。例如,如果您有一个类“Engine”和一个类“Car”,则类“Car”可以有一个类“Engine”的对象。
  • 优点:灵活性更大,类之间的耦合更少。一个类的更改不会直接影响另一个类。

为什么要对继承进行组合?

组合是否优于继承,或者反之亦然,这是软件设计中一个有争议的话题。两种方法都有其优点和缺点,选择取决于具体的项目背景和要求。在这里我将向您展示一个示例,其中组合比继承更可取。

让我们探讨一个 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() 等方法拥有自己的特定逻辑。这种设计更加灵活,可以更轻松地引入新的产品类型或修改特定于类型的逻辑,而不会影响继承层次结构。

什么时候应用继承?

虽然软件设计中继承和组合之间的选择取决于您正在解决的问题的上下文和特定要求。在某些情况下,您可能会认为继承比组合更合适:

  • “is-a”关系:当类之间存在明确的“is-a”关系时,继承尤其合适。如果类 B 是类 A 的更具体或更专业的版本,那么继承就有意义。例如,如果您有一个 Vehicle 类和一个 Car 类,那么“is-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]删除
最新教程 更多>
  • 在 Go 中使用 WebSocket 进行实时通信
    在 Go 中使用 WebSocket 进行实时通信
    构建需要实时更新的应用程序(例如聊天应用程序、实时通知或协作工具)需要一种比传统 HTTP 更快、更具交互性的通信方法。这就是 WebSockets 发挥作用的地方!今天,我们将探讨如何在 Go 中使用 WebSocket,以便您可以向应用程序添加实时功能。 在这篇文章中,我们将介绍: WebSoc...
    编程 发布于2024-11-13
  • Bootstrap 4 Beta 中的列偏移发生了什么?
    Bootstrap 4 Beta 中的列偏移发生了什么?
    Bootstrap 4 Beta:列偏移的删除和恢复Bootstrap 4 在其 Beta 1 版本中引入了重大更改柱子偏移了。然而,随着 Beta 2 的后续发布,这些变化已经逆转。从 offset-md-* 到 ml-auto在 Bootstrap 4 Beta 1 中, offset-md-*...
    编程 发布于2024-11-13
  • 大批
    大批
    方法是可以在对象上调用的 fns 数组是对象,因此它们在 JS 中也有方法。 slice(begin):将数组的一部分提取到新数组中,而不改变原始数组。 let arr = ['a','b','c','d','e']; // Usecase: Extract till index p...
    编程 发布于2024-11-13
  • 除了“if”语句之外:还有哪些地方可以在不进行强制转换的情况下使用具有显式“bool”转换的类型?
    除了“if”语句之外:还有哪些地方可以在不进行强制转换的情况下使用具有显式“bool”转换的类型?
    无需强制转换即可上下文转换为 bool您的类定义了对 bool 的显式转换,使您能够在条件语句中直接使用其实例“t”。然而,这种显式转换提出了一个问题:“t”在哪里可以在不进行强制转换的情况下用作 bool?上下文转换场景C 标准指定了四种值可以根据上下文转换为的主要场景bool:语句:if、whi...
    编程 发布于2024-11-13
  • 如何修复 macOS 上 Django 中的“配置不正确:加载 MySQLdb 模块时出错”?
    如何修复 macOS 上 Django 中的“配置不正确:加载 MySQLdb 模块时出错”?
    MySQL配置不正确:相对路径的问题在Django中运行python manage.py runserver时,可能会遇到以下错误:ImproperlyConfigured: Error loading MySQLdb module: dlopen(/Library/Python/2.7/site-...
    编程 发布于2024-11-13
  • 如何使用 MySQL 查找今天生日的用户?
    如何使用 MySQL 查找今天生日的用户?
    如何使用 MySQL 识别今天生日的用户使用 MySQL 确定今天是否是用户的生日涉及查找生日匹配的所有行今天的日期。这可以通过一个简单的 MySQL 查询来实现,该查询将存储为 UNIX 时间戳的生日与今天的日期进行比较。以下 SQL 查询将获取今天有生日的所有用户: FROM USERS ...
    编程 发布于2024-11-13
  • 如何在 PHP 中组合两个关联数组,同时保留唯一 ID 并处理重复名称?
    如何在 PHP 中组合两个关联数组,同时保留唯一 ID 并处理重复名称?
    在 PHP 中组合关联数组在 PHP 中,将两个关联数组组合成一个数组是一项常见任务。考虑以下请求:问题描述:提供的代码定义了两个关联数组,$array1 和 $array2。目标是创建一个新数组 $array3,它合并两个数组中的所有键值对。 此外,提供的数组具有唯一的 ID,而名称可能重合。要求...
    编程 发布于2024-11-13
  • 使用 html css 和 javascript 的图像滑块 carosual https://www.instagram.com/webstreet_code/
    使用 html css 和 javascript 的图像滑块 carosual https://www.instagram.com/webstreet_code/
    ?带有缩略图和悬停效果的图像轮播? 嘿,开发社区! ? 在我的最新视频中,我构建了一个优雅的图像轮播,其缩略图突出显示具有平滑悬停效果的活动图像。这种交互式设计增强了用户参与度,并为您的 Web 项目增添了现代感。 主要特点: 响应式布局:轮播在所有屏幕尺寸上都能完美调整。 交互式缩略图:可点击的缩...
    编程 发布于2024-11-12
  • React 的核心:理解组件重新渲染
    React 的核心:理解组件重新渲染
    在学习编程语言时,我们经常深入研究语法并专注于快速构建某些东西,有时会忽略一个关键问题:这种语言实际上解决了什么问题,以及它在幕后如何工作?将我们的注意力转移到理解语言的核心目的和机制上,可以让学习速度更快、适应性更强,使我们能够轻松驾驭最复杂的项目。语法总是可以查找的——即使是最经验丰富的开发人员...
    编程 发布于2024-11-12
  • JavaScript 中的 Deferreds、Promise 和 Future 之间有什么区别?
    JavaScript 中的 Deferreds、Promise 和 Future 之间有什么区别?
    JavaScript 中 Deferreds、Promise 和 Future 的区别在 JavaScript 中,deferreds、promise 和 futures 通常用于处理异步操作。这些概念中的每一个都有其独特的一组特征:Deferreds在正式文档中从未明确定义,deferreds 通...
    编程 发布于2024-11-12
  • 为什么我的 Web 应用程序中的请求之间没有维护 Gorilla 会话变量?
    为什么我的 Web 应用程序中的请求之间没有维护 Gorilla 会话变量?
    使用 Gorilla 会话时未维护会话变量问题使用 Gorilla Sessions Web 工具包时,会话变量不会跨请求保留。当服务器启动并且用户访问 localhost:8100/ 时,他们将被定向到 login.html,因为会话值不存在。登录后,会话变量将被存储,并且用户将被重定向到 hom...
    编程 发布于2024-11-12
  • 如何在Python中像“column -t”命令一样显示列化数据?
    如何在Python中像“column -t”命令一样显示列化数据?
    在 Python 中显示列式数据在命令行管理工具领域,通常需要以良好对齐的方式呈现数据列。虽然制表符提供了一种简单的解决方案,但在处理不同长度的数据时它们会失败。本文旨在通过提出受 Linux“column -t”命令行为启发的 Python 解决方案来应对这一挑战。Python 提供了一个强大的解...
    编程 发布于2024-11-12
  • 在 NumPy 数组中查找特定行的有效方法:问题和解决方案
    在 NumPy 数组中查找特定行的有效方法:问题和解决方案
    高效查找 NumPy 数组中特定行的实例使用 NumPy 数组时,可能会遇到需要确定是否array 包含特定行,但 ndarray 的标准 contains 方法引发了问题。本文针对此问题提出了高效且 Python 的解决方案。一种方法涉及使用 .tolist() 将 NumPy 数组转换为 Pyt...
    编程 发布于2024-11-12
  • 如何解决在服务器上使用 Matplotlib 的 Python 脚本的“_tkinter.TclError:无显示名称且无 $DISPLAY 环境变量”问题?
    如何解决在服务器上使用 Matplotlib 的 Python 脚本的“_tkinter.TclError:无显示名称且无 $DISPLAY 环境变量”问题?
    _tkinter.TclError:没有显示名称,也没有 $DISPLAY 环境变量问题使用 Matplotlib 的 Python 脚本在服务器上失败,并出现错误“生成绘图时没有显示名称和 $DISPLAY 环境变量”。出现此问题的原因是 Matplotlib 默认使用 Xwindows 后端,并...
    编程 发布于2024-11-12
  • 如何使用 Apache Commons IO 在 Java 中递归删除目录?
    如何使用 Apache Commons IO 在 Java 中递归删除目录?
    在 Java 中递归删除目录在 Java 中删除空目录非常简单。然而,当处理包含子目录和文件的目录时,该过程变得更加复杂。本文深入探讨了使用 Apache Commons IO 库递归删除整个目录的有效方法。Apache Commons IO 简介Apache Commons IO 提供了一套全面的...
    编程 发布于2024-11-12

免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。

Copyright© 2022 湘ICP备2022001581号-3