单一职责:
简单的 来说,就是一个类,一个方法,一个框架只负责的一件事情。
单一职责原则(SRP:Single responsibility principle)又称单一功能原则,面向对象五个基本原则(SOLID)之一。它规定一个类应该只有一个发生变化的原因。该原则由罗伯特·C·马丁(Robert C. Martin)于《敏捷软件开发:原则、模式和实践》一书中给出的。马丁表示此原则是基于汤姆·狄马克(Tom DeMarco)和Meilir Page-Jones的著作中的内聚性原则发展出的。
所谓职责是指类变化的原因。如果一个类有多于一个的动机被改变,那么这个类就具有多于一个的职责。而单一职责原则就是指一个类或者模块应该有且只有一个改变的原因。
一个类,只有一个引起它变化的原因。应该只有一个职责。每一个职责都是变化的一个轴线,如果一个类有一个以上的职责,这些职责就耦合在了一起。这会导致脆弱的设计。当一个职责发生变化时,可能会影响其它的职责。另外,多个职责耦合在一起,会影响复用性。例如:要实现逻辑和界面的分离。(上述表达来自百度百科)
举列:
Math.round() 只负责四舍五入的方法
Reader 只负责读取文本文件的方法
SpringMVC 只负责简化MVC的开发
举个列子,我之前学习连接数据库的时候,每次对数据库的操作都需要详细实现连接数据库,对数据库内容进行操作两个工作,这时候这个方法里面就有着两个职能。当我需要重新操作的时候,就需要将连接数据库的内容重新写一遍,大大降低了代码的复用性。
“超过5行以上重复的代码,都可以考虑抽取公用的方法
开闭原则:对拓展开放,(对拓展新功能开放)
对修改关闭。(对修改原有功能关闭)
在软件开发的过程中,举个例子,如果在商品一栏中,有一个属性叫做price,这时候我想要给商品打个七折,可以直接这么写:
this.price = price*0.7,
这就显然违背了开闭原则,我们不应当修改源代码,而是应当写个子类继承重写上面的方法。就是不同时候不同的打折力度我们可以通过修改子类来实现,而不是修改源代码。
解释:在我们开发的过程中,服务器端程序员称为作者,客户端程序员称为用户。如druid的开发者可以称为作者,我们这些使用druid的人就是用户。但我们并不是时时刻刻都会拥有作者的源代码,不管有没有都不应该修改源代码,一定要符合开闭原则。
*开闭原则是一个十分重要的原则,必要时刻甚至可以牺牲其它原则为开闭原则让路。
*什么时候用开闭原则,我们写好的类就一定不能改么?如果你是作者,那么你可以随时修改自己的源码,如果你不是作者,那就一定要符合开闭原则
接口隔离原则:接口要小而专,决不能大而全。
因为小接口可以在写类的时候实现多个小接口。
即:使用多个专门的接口比实现一个总接口好。
依赖倒置原则:(面向接口编程)
上层不应该依赖于下层,他们都应当依赖于抽象
先来张图解释一下依赖关系:
这是我在百度图库找的图。上图当中,动物便是依赖于氧气与水,依赖用虚线箭头表示。
依赖关系:是一种使用的关系, 即一个类的实现需要另一个类的协助。
代码表现:局部变量、方法的参数或者对静态方法的调用,下层在上层当中当参数,便可以说上层依赖于下层。
举个例子,如下图,人操作联想,苹果,戴尔等等电脑,人就依赖于这些。这张图属于违背依赖倒置原则的。
实现依赖倒置原则的:
两者都依赖于抽象。
简而言之就是尽可能的使用抽象类型而不是具体类型,因为抽象类型可以被他任意一个子类替代
迪米特法则:(最少知道原则)
一个类对于其它类知道的越少越好,并且之和自己的朋友通信
朋友的定义:
1)当前对象本身(this)
2)以参量形式传入到当前对象方法中的对象
3)当前对象的实例变量直接引用的对象
4)当前对象的实例变量如果是一个聚集,那么聚集中的元素也都是朋友
5)当前对象所创建的对象
迪米特法则是为了降低类之间的耦合度,可以说成是封装的艺术。但是由于通信过程中多了许多小方法(为了使两个成为朋友),降低了通信效率。
设计思路:尽量降低访问权限
里式替换原则:(继承复用的基石)
任何能够使用父类的地方都应该能透明的替换为子类对象,即子类对象可以随时随地的替换父类对象,替换后不报错。
方法重写:在子类和父类中,出现了返回类型相同,方法名相同,参数相同的方法时称为方法的重写。
方法重写的两个限制:
1. 子类重写父类对象时,子类对象修饰符不能比父类更严格。
2. 子类不能抛出比父类更多的异常
限制的原因是;只有保证子类在替换掉父类时不会报错
继承的作用:1.提高代码的灵活性2.多态的前提。
判断能否继承:1. “is a”
2.子类继承父类业务逻辑是否变化,假如变化了则不能继承。
2反例
package demo1;
public class SmartTest {
/*
* 长方形的长需要增加超过宽
*
* */
public void resize(Rectangle r) {
while (r.getHeight() <= r.getWidth()) {
r.setHeight(r.getHeight() + 1);
}
}
}
package demo1;
/*
* 定义一个长方形类
* */
public class Rectangle {
protected long width; // 可以访问基类继承而来的,不能访问基类本身的,对同包内的可见,并且子类也可见
protected long height;
public void setWidth(long width) {
this.width = width;
}
public long getWidth() {
return this.width;
}
public void setHeight(long height) {
this.height = height;
}
public long getHeight() {
return this.height;
}
}
package demo1;
/*
* 定义一个正方形类继承自长方形类
*
*
* */
public class Square extends Rectangle{
public void setWidth(long width, long height) {
this.width = width;
this.height = height;
}
public long getWidth() {
return width;
}
public void setHeight(long height, long width) {
this.height = height;
this.width = width;
}
public long getHeight() {
return height;
}
}
这个正方形很明显在这种需求下无法继承长方形。
组合优于继承:
优先使用组合聚合代码而不是继承
此处的组合指的是“关联”关系
关联:一个类在另一个类当中当字段
可以细分为:组合:鸟和翅膀(关系强)聚合:大雁和雁群(关系弱)
组合优于继承的原因:重写可能撼动整个底层架构。而且只要作者不保证不更新,谁知道他的下一个类不会和你重名呢?
最典型的反例就是现在在java当中的stack类,因为继承的原因使栈的功能不够纯粹。
**使用原则:如果 自己不是作者,那就不要用继承,因为子类不知道自己的重写是否会破坏底层架构。
如果是一个人那么继承毫无问题。
如果仅仅是为了复用别人的代码,难免会出现一些问题