根据维基百科上的解释:开闭原则是软件中的对象(类,模块,函数等等)应该对于扩展是开放的,但是对于修改是封闭的”[1],这意味着一个实体是允许在不改变它的源代码的前提下变更它的行为。
话不多说,下面就让我们一起来coding吧
例如你在某课网上买视频教程学习
package com.geely.design.principle.openclose;
public interface ICourse {
Integer getId();
String getName();
Double getPrice();
}
package com.geely.design.principle.openclose;
public class JavaCourse implements ICourse{
private Integer Id;
private String name;
private Double price;
public JavaCourse(Integer id, String name, Double price) {
this.Id = id;
this.name = name;
this.price = price;
}
public Integer getId() {
return this.Id;
}
public String getName() {
return this.name;
}
public Double getPrice() {
return this.price;
}
}
package com.geely.design.principle.openclose;
public class JavaDiscountCourse extends JavaCourse {
public JavaDiscountCourse(Integer id, String name, Double price) {
super(id, name, price);
}
public Double getDiscountPrice(){
return super.getPrice()*0.8;
}
public Double getOriginPrice(){
return super.getPrice ();
}
}
package com.geely.design.principle.openclose;
public class Test {
public static void main(String[] args) {
ICourse iCourse = new JavaDiscountCourse(96, "Java从零到企业级电商开发", 348d);
JavaDiscountCourse javaCourse = (JavaDiscountCourse) iCourse;
System.out.println("课程ID:" + javaCourse.getId() + " 课程名称:" + javaCourse.getOriginPrice() + " 课程原价:" + javaCourse.getPrice() + " 课程折后价格:" + javaCourse.getDiscountPrice() + "元");
}
}
结果:
这里看到我们打折后的价格丢失了精度,因为本次内容主要不是处理这个问题,所以我就忽略了
附上,类图:
依赖倒置原则的定义如下:
我们该怎么理解上面的定义呢?我们需要咬文嚼字,各个突破。
映射到我们软件实际开发中,一般我们也会将软件进行模块划分,比如业务层、逻辑层和数据层。
业务层中是软件真正要进行的操作,也就是做什么。
逻辑层是软件现阶段为了业务层的需求提供的实现细节,也就是怎么做。
数据层指业务层和逻辑层所需要的数据模型。
抽象如其名字一样,是一件很抽象的事物。抽象往往是相对于具体而言的,具体也可以被称为细节,当然也被称为具象。
理解了上面的概念之后,让我们正式学习依赖倒置原理
在平常的开发中,我们大概都会这样编码。
public class Geely {
public void studyFECourse() {
System.out.println("Geely在学习FE课程");
}
public void studyJAVACourse() {
System.out.println("Geely在学习JAVA课程");
}
}
public class Test {
public static void main(String[] args) {
Geely geely = new Geely();
geely.studyJavaCourse();
geely.studyFECourse();
}
}
这样写其实也是可以的,但是如果geely要学习的课程有很多,这样的话,就不要不断更改Geely类,使代码的复杂度增大了,所以这种面向需求的编程是不推荐的!
而依赖倒置原则正好适用于解决这类情况。
下面,我们尝试运用依赖倒置原则对代码进行改造。
首先是上层模块和底层模块的拆分。
Geely 这个类显然是依赖于ICourse类的,所以,我们的改进是这样子的:
先上类图:
代码如下:
FECourse:
package com.geely.design.principle.dependenceinversion;
public class FECourse implements ICourse {
@Override
public void studyCourse() {
System.out.println("Geely在学习FE课程");
}
}
Geely:
package com.geely.design.principle.dependenceinversion;
public class Geely {
public void setiCourse(ICourse iCourse) {
this.iCourse = iCourse;
}
private ICourse iCourse;
public void studyImoocCourse(){
iCourse.studyCourse();
}
}
ICourse:
package com.geely.design.principle.dependenceinversion;
public interface ICourse {
void studyCourse();
}
javaCourse:
package com.geely.design.principle.dependenceinversion;
public class JavaCourse implements ICourse {
@Override
public void studyCourse() {
System.out.println("Geely在学习Java课程");
}
}
pythonCourse:
package com.geely.design.principle.dependenceinversion;
public class PythonCourse implements ICourse {
@Override
public void studyCourse() {
System.out.println("Geely在学习Python课程");
}
}
Test:
public static void main(String[] args) {
Geely geely = new Geely();
geely.setiCourse(new JavaCourse());
geely.studyImoocCourse();
geely.setiCourse(new FECourse());
geely.studyImoocCourse();
}
定义:不要存在多于一个导致类变更的原因。通俗的说,即一个类只负责一项职责。
package com.geely.design.principle.singleresponsibility;
public class Method {
private void updateUserInfo(String userName,String address){
userName = "geely";
address = "beijing";
}
private void updateUserInfo(String userName,String... properties){
userName = "geely";
// address = "beijing";
}
private void updateUsername(String userName){
userName = "geely";
}
private void updateUserAddress(String address){
address = "beijing";
}
private void updateUserInfo(String userName,String address,boolean bool){
if(bool){
//todo something1
}else{
//todo something2
}
userName = "geely";
address = "beijing";
}
}
其实在实际开发中,单一职责原则是很难实现的
从功能上来看,接口隔离和单一职责两个原则具有一定的相似性。其实如果我们仔细想想还是有区别的。
(1)从原则约束的侧重点来说,接口隔离原则更关注的是接口依赖程度的隔离,更加关注接口的“高内聚”;而单一职责原则更加注重的是接口职责的划分。
(2)从接口的细化程度来说,单一职责原则对接口的划分更加精细,而接口隔离原则注重的是相同功能的接口的隔离。接口隔离里面的最小接口有时可以是多个单一职责的公共接口。
(3)单一职责原则更加偏向对业务的约束,接口隔离原则更加偏向设计架构的约束。这个应该好理解,职责是根据业务功能来划分的,所以单一原则更加偏向业务;而接口隔离更多是为了“高内聚”,偏向架构的设计。
下面是coding接口隔离原则
这里很明显,Boss类已经没有用到Course了,而由TeamLeader直接调用!
最后附上本次设计模式笔记的代码:https://gitee.com/professor_mai/java_design_patterns_/tree/master/