面向对象(精髓)变继承关系为组和关系

在这里插入图片描述
在面向对象编程中,继承关系是一种重要的关系类型,它允许一个类(子类)继承另一个类(父类)的属性和方法。然而,随着软件系统的复杂性不断增加,传统的继承关系可能会导致代码的臃肿和耦合度的增加。为了解决这一问题,我们可以使用组合关系来取代继承关系,将对象的功能模块化,并通过接口定义角色行为,从而实现更加灵活和可维护的设计。本文将探讨面向对象编程中继承关系与组合关系的区别,以及如何合理运用组合关系来优化设计,提高代码的质量和可维护性。

  //面向对象(精髓)变继承关系为组和关系 public Employee(String name, int salary) {this.name = name;this.salary = salary;}public void doWork() {
// 更具需求实现功能}....省略...
public class Manager extends Employee {private final List<Employee> reporters;//下属public void doWork() {
// 项目领导工作给下属分配需求工作}Employee employee1 = new Employee("John", 10000);Employee employee2 = new Employee("Mary", 20000);Employee employee3 = new Employee("John", 10000);//employee2 升级成领导Manager 工资增长5w 并管理其他下属
//打印员工晋升为领导前后的工作内容。

思考如果莫员工(employee2 )升级成领导Manager 怎么优化设计

在这里插入图片描述

不推荐写法(继承关系)

public class Employee {private String name;private int salary;// 构造函数public Employee(String name, int salary) {this.name = name;this.salary = salary;}// 工作方法public void doWork() {// 员工的工作逻辑}
}public class Manager extends Employee {// 管理员属性在这里private List<Employee> reporters;// 管理员的工作方法@Overridepublic void doWork() {// 项目领导的工作逻辑}// 获取下属public List<Employee> getReporters() {return reporters;}
}

在不推荐的继承关系写法中,Manager 类继承自 Employee 类。虽然从某种程度上看,Manager 是一种特殊的 Employee,但这种继承关系存在一些缺点:

  1. 僵化的层次结构:使用继承关系会将 ManagerEmployee 类紧密耦合在一起,形成了僵化的层次结构。如果未来需要引入其他类型的员工,如实习生或兼职员工,就需要修改现有的继承结构,导致系统的扩展性变差。

  2. 不符合"IS-A"关系:继承关系应该满足 “IS-A” 关系,即子类对象可以替代父类对象使用。但 ManagerEmployee 之间的关系不是严格的 “IS-A” 关系。Manager 是一种特殊的员工,但并不是所有员工都是经理。

  3. 职责混淆Manager 类继承了 Employee 类中的一些属性和方法,如 namesalary,但与之相应的 doWork() 方法的实现完全不同。这导致了职责的混淆,使得代码难以理解和维护。

  4. 困难的扩展:在继承关系中,子类继承了父类的全部行为,包括一些可能并不适用于子类的行为。这样就限制了子类的灵活性和可扩展性,使得后续对于子类的修改和扩展变得困难。

综上所述,尽管继承关系在某些情况下很有用,但在这个场景下使用继承关系存在着上述的缺点,因此不推荐使用继承关系来表示 ManagerEmployee 之间的关系。

推荐写法(组合关系)

在这里插入图片描述

// 角色接口
interface Role {void doWork();
}// 工程师角色
class Engineer implements Role {@Overridepublic void doWork() {// 工程师的工作逻辑}
}// 经理角色
class Manager implements Role {private List<Employee> reporters;// 构造函数public Manager(List<Employee> reporters) {this.reporters = reporters;}@Overridepublic void doWork() {// 项目领导的工作逻辑}// 获取下属public List<Employee> getReporters() {return reporters;}
}public class Employee {private String name;private int salary;private Role role; // 当前角色职位// 构造函数public Employee(String name, int salary, Role role) {this.name = name;this.salary = salary;this.role = role;}// 获取当前角色public Role getRole() {return role;}// 执行工作public void doWork() {role.doWork();}}
class Tester{public static void main(String[] args) {Employee employee1 = new Employee("John", 10000);Employee employee2 = new Employee("Mary", 20000);Employee employee3 = new Employee("John", 10000);employee2.doWork();//output 更具需求实现功能...employee2.setRole(new Manager(Arrays.asList(employee1,employee3)));employee2.doWork();//output 项目领导工作给下属分配需求工作...}
}

推荐的组合关系写法采用了 State 模式,相比不推荐的继承关系写法,具有以下优点:

  1. 灵活性和可扩展性:组合关系将角色和功能分离开来,使得系统更加灵活和可扩展。在组合关系中,Employee 类可以根据需要动态地切换不同的角色,而不需要修改现有的代码结构。这样一来,系统可以更加容易地适应需求的变化,保持良好的扩展性。

  2. 降低耦合度:组合关系降低了对象之间的耦合度,使得系统更加灵活和可维护。在组合关系中,Employee 类与具体的角色实现类之间仅通过接口进行交互,彼此之间相互独立。这样一来,系统的各个部分之间的依赖关系更加清晰,代码的耦合度更低,使得系统更加易于理解和维护。

  3. 符合"HAS-A"关系:组合关系符合 “HAS-A” 关系,即一个对象包含另一个对象作为其组成部分。在组合关系中,Employee 类包含了一个 Role 类的引用,表示员工拥有某种角色。这种关系更加贴近现实世界的对象之间的关系,使得系统的设计更加自然和直观。

  4. 清晰的责任分配:组合关系将不同的职责分配到了不同的类中,使得每个类都专注于自己的核心职责。在组合关系中,Employee 类负责管理员工的基本信息,而 Role 接口负责定义员工的角色和行为。这样一来,每个类的职责更加清晰明确,代码更加易于理解和维护。

综上所述,推荐的组合关系写法采用了 State 模式,相比不推荐的继承关系写法,具有更高的灵活性、可扩展性、低耦合度和清晰的责任分配。因此,在设计类和对象时,应该优先考虑使用组合关系,以提高代码的质量和可维护性。

总结

在面向对象设计中,推荐使用组合关系而不是继承关系。组合关系将对象的功能和角色分离,使得对象更加灵活和可复用。通过组合关系,可以将不同的角色和功能组合起来,从而实现更加复杂的行为。同时,组合关系也降低了对象之间的耦合度,使得系统更加易于维护和扩展。因此,在设计类和对象时,应该优先考虑使用组合关系,从而提高代码的质量和可维护性。


扩展阅读

在这里插入图片描述

面向对象主题链接
类与对象链接
接口与抽象类链接
不可变性链接
变继承为组合(精髓)链接

完整代码示例

// 定义状态接口
interface Role {void doWork();
}// 具体状态:普通员工
class Engineer implements Role {@Overridepublic void doWork() {System.out.println("更具需求实现功能...");}
}// 具体状态:经理
class Manager implements Role {private  List<Employee> reporters;public Manager(List<Employee> reporters) {this.reporters = reporters;}@Overridepublic void doWork() {System.out.println("项目领导工作给下属分配需求工作...");}
}
@Data
@AllArgsConstructor
// 上下文类:员工class Employee {private String name;private int salary;private Role role; // 当前角色状态public Employee(String name, int salary) {this.name = name;this.salary = salary;this.role = new Engineer(); // 默认状态为普通员工}// 设置角色状态public void setRole(Role role) {this.role = role;}// 执行工作public void doWork() {role.doWork();}}class Tester{public static void main(String[] args) {Employee employee1 = new Employee("John", 10000);Employee employee2 = new Employee("Mary", 20000);Employee employee3 = new Employee("John", 10000);employee2.doWork();//output 更具需求实现功能...employee2.setRole(new Manager(Arrays.asList(employee1,employee3)));employee2.doWork();//output 项目领导工作给下属分配需求工作...}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/526532.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【国产MCU】-CH32V307-SysTick中断与延时功能实现

SysTick中断与延时功能实现 文章目录 SysTick中断与延时功能实现1、SysTick介绍2、SysTick中断使用3、SysTick实现微秒和毫秒延时功能CH32V307的RISC-V内核控制器自带的一个64位可选递增或递减的计数器,用于产生SYSTICK异常(异常号:15),可专用于实时操作系统,为系统提供“…

Python之Web开发中级教程----搭建Git环境三

Python之Web开发中级教程----搭建Git环境三 多人分布式使用仓库操作实例 场景&#xff1a;开发者A&#xff0c;开发者B在同一个项目协同开发&#xff0c;修改同一个代码文件。开发者A在Win10下&#xff0c;开发者B在Ubuntu下。 1、开发者A修改提交代码 从GitHub: Let’s bu…

在微信小程序项目中使用mock模拟数据

之前对mockjs做了一个介绍&#xff0c;以及在js、vue中拦截ajax的方法&#xff0c;介绍是必看的&#xff0c;也是一些基础 这一篇讲讲在小程序中的应用 微信小程序为了让开发者更方便地开发小程序&#xff0c;开发者工具提供了 API Mock 的能力&#xff0c;可以模拟部分 API 的…

【Apache Camel】基础知识

【Apache Camel】基础知识 Apache Camel是什么Apache Camel基本概念和术语CamelContextEndpointsRoutesRouteBuilderComponentsMessageExchangeProcessorsDomain Specific Language&#xff08;DSL&#xff09; Apache Camel 应用执行步骤Apache Camel 示意图参考 Apache Camel…

机器学习|KNN和Kmeans

KNN和Kmeans KNN KNN-K个最近的邻居&#xff0c;而K是可人先预设出来的。 所谓近朱者赤&#xff0c;近墨者黑。 可以选取离当前最近的K个样本来作为辅助判断&#xff0c;因为本样本和最近的K个样本应该是处于一种相似的状态。 以下是一个苹果和梨的识别任务。 图上会出现一个未…

第十二章执行引擎

第十二章执行引擎 文章目录 第十二章执行引擎0. 前情概述1. 执行引擎的概述1.1 执行引擎的工作过程 2. Java代码编译和执行的过程什么是解释器&#xff1f;什么是JIT编译器&#xff1f;为什么说java是半编译半解释型语言 3. 机器码、指令、汇编语言机器码指令指令集汇编语言高级…

架构面试题汇总:网络协议34问(七)

码到三十五 &#xff1a; 个人主页 心中有诗画&#xff0c;指尖舞代码&#xff0c;目光览世界&#xff0c;步履越千山&#xff0c;人间尽值得 ! 网络协议是实现各种设备和应用程序之间顺畅通信的基石。无论是构建分布式系统、开发Web应用&#xff0c;还是进行网络通信&#x…

主升浪趋势票如何去做,看完这2个例子就可以终结了

我们在这个市场是否能持续赚钱不被淘汰取决于我们自身迭代速度&#xff0c;向市场学习本身就是向市场资金共识方向靠拢&#xff0c;接近客观&#xff0c;远离个人偏见的主观。看清这一点&#xff0c;你才有可能性&#xff0c;否则连可能性都不会有。 在上述问题中&#xff0c;虽…

了解华为(PVID VLAN)与思科的(Native VLAN)本征VLAN的区别并学习思科网络中二层交换机的三层结构局域网VLAN配置

一、什么是二层交换机&#xff1f; 二层交换机&#xff08;Layer 2 Switch&#xff09;是一种网络设备&#xff0c;主要工作在OSI模型的数据链路层&#xff08;第二层&#xff09;&#xff0c;用于在局域网内部进行数据包的交换和转发。二层交换机通过学习MAC地址表&#xff0…

2024年目标检测研究进展

YOLOv9 图片来源网络 YOLO相关的研究&#xff1a;https://blog.csdn.net/yunxinan/article/details/103431338

Openharmony的设备开发流程 Hi3516DV300

安装VirtualBox 这里用VirtualBox 6.1.3 https://download.virtualbox.org/virtualbox/6.1.30/VirtualBox-6.1.30-148432-Win.exe 安装 安装Ubuntu镜像 Ubuntu系统要求&#xff1a;Ubuntu18.04~21.10版本。推荐使用20.04版本&#xff0c;内存16 GB及以上。 https://mirrors…

16. C++标准库

C标准库兼容C语言标准函数库&#xff0c;可以在C标准库中直接使用C语言标准函数库文件&#xff0c;同时C标准库增加了自己的源代码文件&#xff0c;新增文件使用C编写&#xff0c;多数代码放在std命名空间中&#xff0c;所以连接C标准库文件后还需要 using namespace std;。 【…