Java 组合、继承杂谈
一、前言
- Java作为一门面向对象的语言,具备抽象、继承、多态等特性,熟悉Java的人可能对抽象、多态的使用很熟悉,但是却是再继承时需要做一些考量,继承为我们实现“定制化”特性提供了很好的思路,但是滥用继承,并不是一种良好的编程方式。今天,基于自己复习Java基础的同时,聊聊Java中继承和组合的爱恨情仇。
二、基本知识
-
组合
- 简单来说,组合就是在当前类中使用已有类的对象,即新类的功能由已有类的功能组合而成,表示的是 “has a” 关系。一般来说,当希望在新类中使用其功能而不是其接口,切是希望作为一部分”嵌入“进来,这种情况推荐使用组合,新类复用其功能,不复用其形式。
-
继承
- 如果需要在新类中复用已有类的基本功能,并且额外新增一些"特性",不同的新类需要新增的"特性不一样",但是不同新类复用的基本功能均可以有一个已有类提供,那么,这些新类均可以继承这个类,这个类就叫做父类(或者基类),继承的新类叫做子类,子类可以访问基类的非私有属性和方法,从而达到代码的复用。在Java中,继承表示"is a"关系,并且Java仅支持单继承,不支持多继承。
三、应用考量、实际应用
-
什么情况下使用组合
- 考虑这样一个场景,你是一个网管,现在需要你采购一台主机,主机配件包含基本的显示器、主板、CPU、内存等,你需要将采购的这些配件组装起来,合成一台完整的可工作的主机,这些配件作为“一部分”被组装或者说被嵌入你的主机,共同支撑了主机的完整功能。
在这种情况下,配件相对于主机是部分于整体的关系,而部分组件的特性由于主机功能没有直接联系,就可以使用组合来实现。
package main; // Monitor class Monitor { String monitor; public Monitor(String monitor){ this.monitor = monitor; } @Override public String toString() { return "Monitor{" + "monitor='" + monitor + '\'' + '}'; } } // Memory class Memory { String memory; public Memory(String memory){ this.memory = memory; } @Override public String toString() { return "Memory{" + "memory='" + memory + '\'' + '}'; } } // MainBoard class MainBoard { String mainBoard; public MainBoard(String mainBoard){ this.mainBoard = mainBoard; } @Override public String toString() { return "MainBoard{" + "mainBoard='" + mainBoard + '\'' + '}'; } } // Cpu class Cpu { String cpu; public Cpu(String cpu){ this.cpu = cpu; } @Override public String toString() { return "Cpu{" + "cpu='" + cpu + '\'' + '}'; } } class NewComputer{ Cpu cpu = new Cpu("i9-1079k"); Memory memory = new Memory("16G"); MainBoard mainBoard = new MainBoard("MainBoard"); Monitor monitor = new Monitor("京东方"); @Override public String toString() { return "NewComputer{" + cpu + memory + mainBoard + monitor + '}'; } } public class main { public static void main(String[] args) { NewComputer cp = new NewComputer(); String desc = cp.toString(); System.out.println(desc); } }
- 考虑这样一个场景,你是一个网管,现在需要你采购一台主机,主机配件包含基本的显示器、主板、CPU、内存等,你需要将采购的这些配件组装起来,合成一台完整的可工作的主机,这些配件作为“一部分”被组装或者说被嵌入你的主机,共同支撑了主机的完整功能。
-
什么情况下使用继承
-
还是作为网管的场景,为了区分不同用户提供对应的服务,比如VIP和普通用户,我们通常会设置不同的专区,以便于不同的用户体验,VIP区可能会增加茶点、舒适的座椅等额外的服务,同时又和普通用户一样具有主机;普通用户可能没有茶点、座椅是一般的座椅。
这种情况下,VIP和普通用户仅仅是特性上的区别和额外的配置差异,却拥有基本共通的服务选项【主机,座椅,场地】,那么这种就可以使用继承实现,由基类提供通用的服务配置,不同的用户继承并实现对用的专有服务,实现了网吧用户群体的区分管理。
class Computer{ Cpu cpu = new Cpu("i9-1079k"); Memory memory = new Memory("16G"); MainBoard mainBoard = new MainBoard("MainBoard"); Monitor monitor = new Monitor("京东方"); public void desc(String desc){ System.out.println(desc); } @Override public String toString() { return "NewComputer{" + cpu + memory + mainBoard + monitor + '}'; } } class NewVIPComputer extends Computer{ public void getComputer() { desc("hello, VIP"); System.out.println("this is a vip computer"); } @Override public void desc(String desc) { super.desc(desc); } } class NewNormalComputer extends Computer{ public void getNormalComputer() { desc("hello, Normal"); System.out.println("this is a normal computer"); } @Override public void desc(String desc) { super.desc(desc); } } public class main { public static void main(String[] args) { new NewVIPComputer().getComputer(); new NewNormalComputer().getNormalComputer(); } }
-
-
什么情况可以混合使用
- 看完以上两个场景,相信你已经知道怎么使用组合和继承了,那么混合使用组合和继承,共同实现网吧的基本服务功能,应该是水到渠成。一般来说,网吧会采购不同主机,会有用户群体的区分,服务的差异,区分哪些部分使用继承,哪些部分使用组合,可以根据其关系来初步识别,如果子类和基类是“嵌入作为部分”,那么适用于组合,如果子类和基类是“相似有具有特性”,那么则可以使用继承,当然实现功能的方式千千万,本文仅仅是基于组合和继承的使用场景进行讨论,并不一定代表实际使用。还有一个场景也类似,那就是汽车经营店汽车的组装和管理,基本也是类似原理,想想是不是这样呢。