开闭原则
定义:一个软件实体如类、模块和函数应该对扩展开发,对修改关闭
用抽象构建框架,用实现拓展细节
优点:提高软件系统的可复用性及可维护性
核心思想:面向抽象编程,而不是面向具体的实现编程,因为抽象相对来说是稳定的,让类去依赖于固定的抽象,所有对修改来说说就是封闭的。通过面向对象的继承和多态的机制,可以实现对抽象体的继承,通过重写改变其固有方法,或者实现新的扩展方法。当变化发生,时,可以通过创建抽象来隔离以后有可能发生的同类变化
下面实现代码,我想要一个女神,想要她符合我几个要求,胸大,腰好,萝莉范
//创建一个接口,三个变量,你心里目中的女神属性
public interface Girlfriend {
Integer bust(); //胸围
String figure();//身材
String type(); //哪种气质女生
}
创建女神的接口实现类
public class Goddess implements Girlfriend {
private Integer bust;
private String figure;
private String type;
public Goddess(Integer bust, String figure, String type) {
this.bust = bust;
this.figure = figure;
this.type = type;
}
@Override
public Integer bust() {return this.bust; }
@Override
public String figure() {return this.figure;}
@Override
public String type() {return this.type; }
}
- 假设我们要给我们的女神增加胸围,这样符合我们的要求 ,
- 我不需要在接口里面添加,可以重写父类方法,原来的方法属性也不会丢失
public class GoddessType extends Goddess {
public GoddessType(Integer bust, String figure, String type) {
super(bust, figure, type);
}
//我还要原来的胸围做对比
public Integer Orginbust(){
return super.bust();
}
//新增女神的特点,我想要女神是胸围更大一点,36d的
//我在接口里面定义新的方法,那么女神实现类就要发生更改
//但是这就会发生臃肿,你的女神整体都要更改。
//接口,应该是稳定可靠的,不应该经常变动的
//重写父类的bust方法
@Override
public Integer bust() {//越来越好
return super.bust()+12;
}
}
然后我们new一个我们想要的女神出来
public class MyDayDream {
public static void main(String[] args) {
Girlfriend girlfriend = new GoddessType(24,"水蛇腰","小萝莉");
GoddessType goddess = (GoddessType) girlfriend;
System.out.println("你做梦的女神:她是一个有着" + goddess.bust() + "d令人垂涎"+
goddess.figure() +"身材,人见人爱的"+ goddess.type() + ",虽然胸围只有"
+ goddess.Orginbust()+"d");
}
}
输出
你做梦的女神:她是一个有着36d令人垂涎水蛇腰身材,人见人爱的小萝莉,虽然胸围只有24d
虚线是接口,实现是继承,子类构造器GoddessType调用父类的构造器
2、依赖倒置原则
- 定义:高层模块不应该依赖底层模块,二者都应该依赖其抽象
- 抽象不应该依赖细节;细节应该依赖抽象
- 针对接口编程,不要针对实现编程。使模块类之间彼此独立互不影响,从而实现模块之间的松耦合,降低模块之间的耦合性
实现结构:一个小明在CSDN上学习,可能对java课程感兴趣,对python也感兴趣,突然某一天帅哥想去学习大数据,那么实体课程就需要不断补充,你要是面向实现编程,因为小明这个类就是实现类,一直要扩展,扩展性很差。
应用层的函数,是依赖于底层实现的,要是没有抽象,就会依赖于小明这个类,现在属于高层次模块依赖于低层次模块。应用层,实现什么都要去帅哥类里面去扩展,这是不可取的。
下面引入抽象,具体代码
首先创建接口,具体学习什么课程,交给高层模块的应用层来选择
public interface ICourse {
void studyCourse();
}
来实现接口,这个课程类
创建三种不同课程学习
java课程学习、python课程学习、data课程学习
public class JavaCourse implements ICourse {
@Override
public void studyCourse() {
System.out.println("XiaoMing在学习Java课程");
}
}
public class PythonCourse implements ICourse {
@Override
public void studyCourse() {
System.out.println("XiaoMing在学习Python课程");
}
}
public class DataCourse implements ICourse {
@Override
public void studyCourse() {
System.out.println("Xiaoing在学习大数据课程");
}
}
这里就是xiaoming在学校CSDN课程的时候,具体的实现类交给高层次模块
而不是针对xiaoming这个实现类来编写
public class XiaoMing {
public void studyCSDNCourse(ICourse iCourse){
iCourse.studyCourse();
}
}
public class Test {
public static void main(String[] args) {
XiaoMing xiaoming = new XiaoMing();
xiaoming.studyCSDNCourse(new JavaCourse());
xiaoming.studyCSDNCourse(new DataCourse());
xiaoming.studyCSDNCourse(new PythonCourse());
}
}
输出
XiaoMing在学习Java课程
XiaoMing在学习大数据课程
XiaoMing在学习Python课程
首先ICourse这个接口放这边,要是其他的课程实现,前端课程实现,和下面的java,python课程平级,而具体的xiaoming这个类是不需要动的,我们要是面向接口编程,我们要写的扩展类是面向接口的,而不是面向具体的xiaoming实现类,而高层模块,具体学习什么交给test来选择,这样就做到了xiaoming和test之间是解耦的,同时xiaoming和具体的课程实现是解耦的,但是xiaoming是跟ICourse是有耦合的
所谓的高内聚低耦合,就是尽量减少耦合
单一职责原则
定义:不要存在多于一个导致类变更的原因。假设有一个类class,负责两个职责,职责1和职责2,一旦需求变更,职责相关的功能需要发生改变,那么修改这个class类的时候,有可能会导致原本运行正常的职责2方式故障,这既是创建class没有遵循单一职责原则
体现在一个类、接口、方法、只负责一项职责
优点:降低类的负责度、提高类的可读性,提高系统的可维护性,降低变更引起的风险。
这要是模块的数据都可以使用单一职责原则
设计结构:老鹰和老母鸡属于鸟,老鹰是用翅膀飞的,老母鸡是用脚走的
代码实现
public class Bird {
public void mainMoveMode(String birdName){
if("老母鸡".equals(birdName)){
System.out.println(birdName+"用脚走");
}else{
System.out.println(birdName+"用翅膀飞");
}
}
}
public class FlyBird {
public void mainMoveMode(String birdName){
System.out.println(birdName+"用翅膀飞");
}
}
public class WalkBird {
public void mainMoveMode(String birdName){
System.out.println(birdName+"用脚走");
}
}
public class Test {
public static void main(String[] args) {
FlyBird flyBird = new FlyBird();
flyBird.mainMoveMode("老鹰");
WalkBird walkBird = new WalkBird();
walkBird.mainMoveMode("老母鸡");
}
}
输出
老鹰用翅膀飞
老母鸡用脚走