类设计
面向对象
面向对象编程
是一种编程范式或编程风格。它以类或对象作为组织代码的基本单元,并将封装、抽象、继承、多态四大特性,作为代码设计和实现的基石。
面向对象编程语言
是支持类或对象的语法机制,并有现成的语法机制,能方便的实现面向对象编程四大特性的编程语言。
面向对象开发
包括面向对象分析 OOA、面向对象设计 OOD、面向对象编程 OOP。
继承
继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。重写和重载(www.runoob.com/java/java-o…
封装
规定了哪些代码可以被调用。
-
- 良好的封装能够减少耦合。
-
- 类内部的结构可以自由修改。
-
- 可以对成员变量进行更精确的控制。
-
- 隐藏信息和实现细节。
多态
提现为接口的重写。
类
对象的模板,通过类来创造对象。规定了对象的属性和行为
抽象类、方法
Abstract。 具体实现由子类继承或实现。
抽象类总结规定
-
- 抽象类不能被实例化(初学者很容易犯的错),如果被实例化,就会报错,编译无法通过。只有抽象类的非抽象子类可以创建对象。
-
- 抽象类中不一定包含抽象方法,但是有抽象方法的类必定是抽象类。
-
- 抽象类中的抽象方法只是声明,不包含方法体,就是不给出方法的具体实现也就是方法的具体功能。
-
- 构造方法,类方法(用 static 修饰的方法)不能声明为抽象方法。
-
- 抽象类的子类必须给出抽象类中的抽象方法的具体实现,除非该子类也是抽象类。
interface、implements
特性:
- 接口中每一个方法也是隐式抽象的,接口中的方法会被隐式的指定为 public abstract(只能是 public abstract,其他修饰符都会报错)。
- 接口中可以含有变量,但是接口中的变量会被隐式的指定为 public static final 变量(并且只能是 public,用 private 修饰会报编译错误)。
- 接口中的方法是不能在接口中实现的,只能由实现接口的类来实现接口中的方法。
抽象类和接口的区别
- 抽象类中的方法可以有方法体,就是能实现方法的具体功能,但是接口中的方法不行。
- 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是 public static final 类型的。
- 接口中不能含有静态代码块以及静态方法(用 static 修饰的方法),而抽象类是可以有静态代码块和静态方法。
- 一个类只能继承一个抽象类,而一个类却可以实现多个接口。
枚举
枚举跟普通类一样可以用自己的变量、方法和构造函数,构造函数只能使用 private 访问修饰符,所以外部无法调用。
枚举既可以包含具体方法,也可以包含抽象方法。 如果枚举类具有抽象方法,则枚举类的每个实例都必须实现它。
public enum AbstractEnum {
/** 线程状态 **/
NEW{
@Override
public void dosomething(){
System.out.println("创建的新的线程");
}
};
public abstract void dosomething();
}
10大原则
1 单一职责原则 SRP
实现类要职责单一
如果一段代码块(函数 类 模块)负责多个功能,那么当 A 功能需求发生改变的时候改动了代码,就有可能导致 B 功能出现问题,所以一段代码块只应该负责一个职责。
2 开闭原则 OCP
对扩展开放,对修改关闭
在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类。它是说我们在实现一个新功能时,首先应该想到的是扩展原来的功能,而不是修改之前的功能。
随着软件越做越大,对应的客户端版本也越来越多,而这些客户端都是安装在用户的手机上。因此我们不能保证所有用户手中的 App(客户端)都一直是最新版本的,并且也不能每次都强制用户进行升级或者是协助用户去升级,开发新功能时,就强制要求团队人员不允许直接修改原来的老接口,而是要在原有的接口上进行扩展升级。
3 里氏代换原则 LSP
不要破坏继承体系,任何基类可以出现的地方,子类一定可以出现
程序中的子类应该可以替换父类出现的任何地方并保持预期不变。所以子类尽量不要改变父类方法的预期行为。LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。
4 依赖倒转原则 DIP
面向接口编程
抽象不应该依赖细节,细节应该依赖于抽象。核心是面向接口编程,我们应该依赖于抽象接口,而不是具体的接口实现类或具体的对象。
5 接口隔离原则 ISP
设计接口的时候要精简单一
使用多个隔离的接口,比使用单个接口要好。当类 A 只需要接口 B 中的部分方法时,因为实现接口需要实现其所有的方法,于是就造成了类 A 多出了部分不需要的代码。这时应该将 B 接口拆分,将类A需要和不需要的方法隔离开来。降低类之间的耦合度的意思。
注:SOLID 又称为5大设计原则
6 迪米特法则(最少知道原则)LOD
降低耦合度
为什么叫最少知道原则,就是说:一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。一个类或对象应该对其它对象保持最少的了解。只与直接的朋友(耦合)通信。
7 组合/聚合复用原则(合成复用原则) CRP
多用组合少用继承
原则是尽量使用合成/聚合的方式,而不是使用继承。
8 不要重复你自己 DRY
代码逻辑重复但语义不同应该保留,功能语义重复应该合并,代码执行重复应该删减。
9 精良保持简单 KISS
尽可能使用简单可读性高的代码实现功能,而不用逻辑复杂、实现难度高、可读性差的方式。
10 不要过度设计暂时用不到的逻辑 YAFGNI
不要过度优化、不要过度预留扩展点、不要设计同事看不懂的代码。
高质量代码:
- 可读性、可扩展性、可维护性、可复用性、可测试性...
- 高内聚低耦合# 类设计
面向对象
面向对象编程
是一种编程范式或编程风格。它以类或对象作为组织代码的基本单元,并将封装、抽象、继承、多态四大特性,作为代码设计和实现的基石。
面向对象编程语言
是支持类或对象的语法机制,并有现成的语法机制,能方便的实现面向对象编程四大特性的编程语言。
面向对象开发
包括面向对象分析 OOA、面向对象设计 OOD、面向对象编程 OOP。
继承
继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。重写和重载(www.runoob.com/java/java-o…
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gm2HMivB-1666058093521)(bed.thunisoft.com:9000/ibed/2022/0…)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QCSBEeMz-1666058093521)(C:\Users\cc\AppData\Roaming\Typora\typora-user-images\image-20220509103906844.png)]
封装
规定了哪些代码可以被调用。
-
- 良好的封装能够减少耦合。
-
- 类内部的结构可以自由修改。
-
- 可以对成员变量进行更精确的控制。
-
- 隐藏信息和实现细节。
多态
提现为接口的重写。
类
对象的模板,通过类来创造对象。规定了对象的属性和行为
抽象类、方法
Abstract。 具体实现由子类继承或实现。
抽象类总结规定
-
- 抽象类不能被实例化(初学者很容易犯的错),如果被实例化,就会报错,编译无法通过。只有抽象类的非抽象子类可以创建对象。
-
- 抽象类中不一定包含抽象方法,但是有抽象方法的类必定是抽象类。
-
- 抽象类中的抽象方法只是声明,不包含方法体,就是不给出方法的具体实现也就是方法的具体功能。
-
- 构造方法,类方法(用 static 修饰的方法)不能声明为抽象方法。
-
- 抽象类的子类必须给出抽象类中的抽象方法的具体实现,除非该子类也是抽象类。
interface、implements
特性:
- 接口中每一个方法也是隐式抽象的,接口中的方法会被隐式的指定为 public abstract(只能是 public abstract,其他修饰符都会报错)。
- 接口中可以含有变量,但是接口中的变量会被隐式的指定为 public static final 变量(并且只能是 public,用 private 修饰会报编译错误)。
- 接口中的方法是不能在接口中实现的,只能由实现接口的类来实现接口中的方法。
抽象类和接口的区别
- 抽象类中的方法可以有方法体,就是能实现方法的具体功能,但是接口中的方法不行。
- 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是 public static final 类型的。
- 接口中不能含有静态代码块以及静态方法(用 static 修饰的方法),而抽象类是可以有静态代码块和静态方法。
- 一个类只能继承一个抽象类,而一个类却可以实现多个接口。
枚举
枚举跟普通类一样可以用自己的变量、方法和构造函数,构造函数只能使用 private 访问修饰符,所以外部无法调用。
枚举既可以包含具体方法,也可以包含抽象方法。 如果枚举类具有抽象方法,则枚举类的每个实例都必须实现它。
public enum AbstractEnum {
/** 线程状态 **/
NEW{
@Override
public void dosomething(){
System.out.println("创建的新的线程");
}
};
public abstract void dosomething();
}
10大原则
1 单一职责原则 SRP
实现类要职责单一
如果一段代码块(函数 类 模块)负责多个功能,那么当 A 功能需求发生改变的时候改动了代码,就有可能导致 B 功能出现问题,所以一段代码块只应该负责一个职责。
2 开闭原则 OCP
对扩展开放,对修改关闭
在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类。它是说我们在实现一个新功能时,首先应该想到的是扩展原来的功能,而不是修改之前的功能。
随着软件越做越大,对应的客户端版本也越来越多,而这些客户端都是安装在用户的手机上。因此我们不能保证所有用户手中的 App(客户端)都一直是最新版本的,并且也不能每次都强制用户进行升级或者是协助用户去升级,开发新功能时,就强制要求团队人员不允许直接修改原来的老接口,而是要在原有的接口上进行扩展升级。
3 里氏代换原则 LSP
不要破坏继承体系,任何基类可以出现的地方,子类一定可以出现
程序中的子类应该可以替换父类出现的任何地方并保持预期不变。所以子类尽量不要改变父类方法的预期行为。LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。
4 依赖倒转原则 DIP
面向接口编程
抽象不应该依赖细节,细节应该依赖于抽象。核心是面向接口编程,我们应该依赖于抽象接口,而不是具体的接口实现类或具体的对象。
5 接口隔离原则 ISP
设计接口的时候要精简单一
使用多个隔离的接口,比使用单个接口要好。当类 A 只需要接口 B 中的部分方法时,因为实现接口需要实现其所有的方法,于是就造成了类 A 多出了部分不需要的代码。这时应该将 B 接口拆分,将类A需要和不需要的方法隔离开来。降低类之间的耦合度的意思。
注:SOLID 又称为5大设计原则
6 迪米特法则(最少知道原则)LOD
降低耦合度
为什么叫最少知道原则,就是说:一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。一个类或对象应该对其它对象保持最少的了解。只与直接的朋友(耦合)通信。
7 组合/聚合复用原则(合成复用原则) CRP
多用组合少用继承
原则是尽量使用合成/聚合的方式,而不是使用继承。
8 不要重复你自己 DRY
代码逻辑重复但语义不同应该保留,功能语义重复应该合并,代码执行重复应该删减。
9 精良保持简单 KISS
尽可能使用简单可读性高的代码实现功能,而不用逻辑复杂、实现难度高、可读性差的方式。
10 不要过度设计暂时用不到的逻辑 YAFGNI
不要过度优化、不要过度预留扩展点、不要设计同事看不懂的代码。
高质量代码:
- 可读性、可扩展性、可维护性、可复用性、可测试性...
- 高内聚低耦合