类和类之间的关系与七大原则

一、类与类之间的关系:
1.B类继承A类
在这里插入图片描述
2.关联关系
A 在 字段位置。
在这里插入图片描述
箭头指向问题:被关联的是被指向的。(B关联A A被关联 箭头指向A)
在这里插入图片描述

3.依赖关系
A作为B的形参或者局部变量,则成为B 依赖于 A。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
4.关联关系细分为组合和聚合
关系强:组合(如鸟和翅膀) 实心菱形
关系弱:聚合(如大雁和雁群)空心菱形

二、七大原则

1.单一职责原则

每个方法、每个类、每个框架都只负责一件事情。

比如:
Math.round().只负责完成四舍五入的功能,其他的不管。

Reader类,只负责读取文本文件。

SpringMVC 只负责简化MVC的开发(框架)。

package sevenprinciple;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.Reader;
public class AppTest {
	public static void main(String[] args) throws Exception {
		
		//统计一个文本文件中,有多少个字符。
		//使用字符流   不使用字节流
		//Reader默认查询的码表是与操作系统一致的码表,我们的操作系统是中文的
		//所以Reader就会使用GBK码表
		//GBK码表一个汉字占2个字节,且汉字的两个字节都是以1开头的。
		//读取到记事本中的数字--->gbk--->北--->unique--->
		//字符流会查码表,字节流不会查码表。操作文本文件用字符流。
		Reader in = new FileReader("C:\\Users\\李昊\\Desktop\\1.txt");
		int n;
		int count = 0;
		while((n=in.read())!=-1){
			count++;
		}
		System.out.println(count);
		in.close();
	}
}

在这里插入图片描述
问题分析
在此编程过程中,一个方法中,不仅进行了整行的读取,同时还进行了单词的分割,这不符合单一职责原则
以上代码违反了单一职责原则,缺点是:
1.代码的重用性不高,如果有其他需求,必须需要统计一个文件中的句子数量,则必须把文件加载到字符串中的代码,再写一遍。
2.可读性低,别人一看这个方法,首先会被具体的算法搞晕,看代码的人根本看不出这个代码要干什么。
修改过程:
抽取出方法,仅进行文件的读取工作。
在这里插入图片描述
在这里插入图片描述
进一步处理:
在这里插入图片描述
现在的代码就符合单一职责了。优点如下:
1.代码重用性提高了。
2.代码可读性提高了,此时的代码,就像一个大纲一样的。
3.降低耦合性 每个方法具有明确分工。明确设计原则的背后是分。

2.开闭原则
a.对扩展开放
b.对修改关闭
比如: 有一个刮胡刀,刮胡刀的作用就是刮胡子,现在想让刮胡刀具备吹风机能力。
违反开闭原则的做法就是,把吹风功能加上了,可能不能刮胡子了。
符合开闭原则的做法就是:把吹风功能加上了,且没有影响以前的刮胡子功能。

补充
如果,一个类从头到尾都是你自己创造编写的,那么你可以随时随地修改源代码,因为作者就是你。
如果一个类不是你写的,而是别人写的,那就不能修改别人的代码了,而要符合开闭原则。
举例:
在这里插入图片描述
在这里插入图片描述
变化来了:
现在所有汽车需要打8折!!
违反开闭原则的做法就是,直接打开Car的源代码,在getPrice上修改
在这里插入图片描述

符合开闭原则的做法是,始终保持car的源代码不会被修改。我们可以这样做:创建一个Car的子类重写Car的getPrice方法。
在这里插入图片描述
在这里插入图片描述
3.接口隔离原则
使用多个专门的接口比使用一个单一的接口要好。
反例:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
正例:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
4.依赖倒置原则
概念:上层不能依赖于下层,他们都应该依赖抽象
什么是上层?什么是下层?
调用别的方法的,就是上层,被其他方法调用的,就是下层。
在这里插入图片描述
变化来了,客户端不仅仅需要喂狗,还需要喂猫!
客户端给自己定义一个猫类。
在这里插入图片描述
如果修改,违反了开闭原则:
在这里插入图片描述
违反依赖倒置的图解
在这里插入图片描述
此时,这种代码违反了依赖倒置,因为,每当下层变动时,上层都要跟着一起变动。(新增一个tiger类 person 就要增加一个喂养tiger的方法。)
我们希望的是,当下层新增一个动物时,上层应该“不知道”,上层代码应该不用改动。
修改代码:让新增加的类 实现animal接口。
在这里插入图片描述

在这里插入图片描述
符合依赖倒置原则的图解:
在这里插入图片描述
下层代码变动时,上层代码不发生变动。箭头本来是往下,后来箭头倒过来了。将依赖进行了倒置。 接口是一个抽象层,上层就依赖于抽象层了,下层也依赖于抽象了(实现接口。)这样做的好处是,只要实现类统统实现接口,就不需要修改上层代码了。这样就把上下层“分”开了。

5.迪米特法则(最少知道原则)
一个类,对于其他类,要知道的越少越好。
只和朋友通信。

反例
在这里插入图片描述
反例说明的问题:此时这个Person 对于Computer的细节就知道的太多了。
对于Person而言,只需要知道关机按钮在哪就行,不需要知道如何保存数据,如何关闭进程。如何断电等等这些细节。这样的话,代码的复杂度就提升了。万一用户使用不当,就有可能造成更大的损失。
修改代码:
在Computer内部设定shutDown方法,而不在Person类中暴露,直接调用。
在这里插入图片描述

在这里插入图片描述

什么是朋友?
a.类中的字段 b.方法的参数 c.方法的返回值 d. 方法中实例化 new 出来的对象
是朋友什么方法都能调用。

举例:不是朋友的例子:
在这里插入图片描述

图中的bar就不是朋友,因为并不是方法中实例化new的对象,而是通过f 调用的对象。

6.里式替换原则
任何能使用父类对象的地方,都应该能透明地替换为子类对象。也就是说子类对象可以随时随地替换父类对象,且替换完以后,语法不会报错,业务逻辑也不会出现问题!

方法重写:在子类和父类中,出现了返回类型相同、方法名相同、方法参数相同的方法时,构成方法重写。
方法重写的两个限制:
1.子类重写父类的方法时,子类方法的访问修饰符不能比父类的更严格。
2.子类重写父类方法时,子类方法不能抛出比父类更多的异常。

为什么要有以上这两个限制?就是为了保证在子类对象替换父类对象后,语法不会报错。为了保证代码符合里式替换原则。

继承的作用:
1.提高代码的重用性。
2.多态的前提。

两个类能不能发生继承关系的依据是什么 ?
a.主要看有没有“ is a ”关系。
b.在两个类有了is a 关系之后,还要考虑子类对象在替换了父类对象之后,业务逻辑是否变化。如果变化,则不能发生继承关系。

正方形和长方形有 “ is a ” 关系。那我们能不能让正方形类就直接去继承长方形类呢?现在不能了!!
为什么呢? 因为还要考虑业务场景,在特定的业务场景下,正方形能替换了长方形以后,业务逻辑是否变化!
正方形 长方形 那些事儿。

7.组合优于继承
继承:一个类优于另外一个类。
我们已经知道,类和类之间有3中关系:
a.继承
b.依赖
c.关联
我们又知道,其中“关联”可以细分为:
a.组合
b.聚合

所谓的组合,是关系强,聚合是关系弱。

组合优于继承中的组合,其实就是指的关联关系。
需求:制作一个集合,要求该集合能记录曾经加过多少个元素,不是统计某一时刻集合中有多少个元素。

举例:
在这里插入图片描述
在这里插入图片描述
经计算,结果为6.理由:addAll 回调了add方法。所以,这样的代码没有解决需求。
在这里插入图片描述
针对于a包中的问题,addall会回调add方法,我们修改代码如下,把addAll删除掉,不要重写父类Hashset的addAll了,反正父类的addALL本身就会去回调add.

此时,这个代码看起来好像很完美,几乎是满足需求了。问题是: 目前这个代码必须依赖于这样一个事实,就是HashSet的addAll方法必须去回调add方法。
万一将来的jdk版本中, HashSet的addALL实现代码,突然不再回调add方法了,则在将来的这个jdk版本中,我们自定义的这个mySet就被撼动。
比如HashMap 在1.6 1.7 1.8中 换了3次!
针对于以上问题,Myset必须依赖于这样一个事实,addAll必须回调add, 但是jdk未来的版本,不会做这个保证!修改代码如下:我们自己亲自重写addAll,不再让count累加c.size()了,而是保证addAll 一定会回调add.
在这里插入图片描述
问题是:
1.如果在新的jdk版本中,Hashset突然多了一个元素加入集合的入口方法,addSome,这个addSome 是我们始料未及的,我们没有重写addSome方法,但在新版本中,我们的Myset也继承了addSome方法,当使用addSome方法添加元素时,根本不会去统计元素的数量。
2.我们重写了addAll方法和add方法,要知道,在整个Hashset的所有方法中,难免有一些其他方法,会依赖于addAll方法会依赖于add方法。我们没头没脑的重写了别人类中的某些方法,就会导致其他依赖于这些方法的方法,出现问题。

修改代码如下:
1.不再重写add和addAll方法。
2.我们额外制作2个代替add和addAll的方法 add2 和addAll2,还要在类中生成API文档,在文档中说明,每当要使用add 和addAll 的时候,都要去调用add2 和addAll2
出现问题:
1.目前这种情况对用户要求有点过分,用户必须看类的api文档,看完了还要乖乖地使用add2 和addAll2.
2.更致命的问题是,就是那么寸,在jdk新版本中,HashSet恰恰多了一个api,叫add2 和addAll2.

继承,已经尽忠了…

针对于上述问题,修改代码如下:
1.MySet 不再继承HashSet .
2.取而代之,让MySet 和HashSet发生关联关系(组合)
在这里插入图片描述
由于没有重写add方法,所以,count 不会重新把每个元素计入。
解决了以下问题:
1.没有重写,addALL 和add 问题解决。也就是计数不会出现错误。同时,也不会出现其他方法调用add 和addAll方法时出现错误的问题。
2,.由于组合中无法提供addSome方法,所以addSome方法问题得到解决。

问题:
1.难道以后都不能使用继承了吗?

2.难道以后都不能进行方法重写了吗?

如果父类作者和子类的作者不是同一个人时,不继承。那么父类作者,不知道未来的子类会重写自己的哪个方法。那么子类作者,也不知道未来的父类会加入什么新方法。
如果父类的作者和子类的作者就是同一个人,那就可以放开手脚去使用继承了!自己当然知道,每个方法都是什么作用。作者可以同时控制父类和子类。
我们自己写代码,继承、重写、随便使用。
如果我们仅仅是为了复用代码,而继承别人的类,难免出现“沟通”上的问题。

现实生活中出现的反例:Stack 继承了Vector

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值