写在最前
设计模式
推荐浏览:软件设计模式
- 代表了代码的最佳实践,被有经验的开发人员所使用;
- 设计模式是很多被反复使用并知晓的,主要是对代码和经验的总结;
- 使用设计模式是为了重用代码,让代码更容易被他人理解,保证代码的可靠性;
- 对接口编程而不是对实现变成;
- 有限使用对象组合而不是继承关系;
设计原则
设计模式的六大设计(第七点为后增)原则通常是指的面向对象设计原则,也被称为SOLID原则。这六大设计原则分别是:
-
单一职责原则(Single Responsibility Principle,SRP):
- 一个类应该只有一个引起变化的原因。这意味着一个类应该只有一个责任,只关注一个功能领域;
- 降低程序的复杂度,提高程序可维护性,降低了变更所带来的风险;
-
开放/封闭原则(Open/Closed Principle,OCP):
- 软件实体(类、模块、函数等)应该是可扩展的,但不可修改的。即,对于新增功能应通过扩展而不是修改现有代码来实现;
- 使用抽象进行构建,使用实现扩展细节,面向抽象编程;
- 提高软件系统的可复用性和可维护性;
-
里氏替换原则(Liskov Substitution Principle,LSP):
- 所有引用基类的地方必须能够透明地使用其子类的对象,即子类可以替代基类而不影响程序的正确性;
- 里氏替换原则是继承复用的基石,对开闭原则的补充;
- 子类可以实现父类的抽象方法,但是不能覆盖原有父类的方法,子类中可以增加自己特有的方法;
- 可以增加程序的健壮性;
-
接口隔离原则(Interface Segregation Principle,ISP):
- 一个类对于它的客户端应该只暴露它们需要的方法,而不应该强迫客户端使用它们不需要的方法。接口应该是客户端特定的,而不是通用的;
- 尽量细化接口,接口中的方法尽量少;
- 符合低耦合的设计思想,提高了可扩展性和可维护性;
-
依赖倒置原则(Dependency Inversion Principle,DIP):
- 高层模块不应该依赖于低层模块,而是两者都应该依赖于抽象。抽象不应该依赖于具体实现,而具体实现应该依赖于抽象;
- 依赖倒置原则是开闭原则的基础,针对接口进行编程;
- 可以减少类之间的耦合行,提高系统稳定性,提高代码可读性和可维护性;
- 降低修改程序所造成的风险;
-
迪米特法则(Law of Demeter,LoD):
- 一个对象应该对其他对象有最少的了解,即一个对象不应该直接调用另一个对象内部的方法,而应该通过一些中介者来进行间接调用;
- 为了降低类与类之间的耦合关系;
- 强调只和朋友交流,不和陌生人说话。朋友指的是成员变量或方法中输入输出的参数;
-
合成复用原则(Composite Reuse Principle,CRP):
- 尽量使用对象组合,聚合的方式,而不是使用继承关系达到软件复用的目的;
- 可以使系统更加灵活,降低类与类之间的耦合度,一个类的变化对其他类造成的影响相对较少;
这些设计原则共同为面向对象设计提供了指导方针,有助于创建更灵活、可维护和可扩展的代码。在应用这些原则时,设计模式通常被用来实现这些原则的具体设计方案。
单一职责原则
1.定义人类接口
人类都具有吃饭、睡觉的行为
csharp
public interface Human {
/**
* 吃饭
*/
void eat();
/**
* 睡觉
*/
void sleep();
}
2.定义程序员抽象类
程序员都需要工作
csharp
public abstract class Programmer implements Human {
/**
* 程序员都需要工作
*/
abstract void work();
}
3.Java程序员
具备Java编写能力
csharp
public class JavaProgrammer extends Programmer {
@Override
public void eat() {
System.out.println("Java程序员在吃饭");
}
@Override
public void sleep() {
System.out.println("Java程序员在睡觉");
}
@Override
void work() {
System.out.println("Java程序员在工作");
}
/**
* Java程序员其他行为
*/
void codeJava() {
System.out.println("Java程序员在写Java代码");
}
}
4.测试
typescript
public class Test {
public static void main(String[] args) {
JavaProgrammer javaProgrammer = new JavaProgrammer();
javaProgrammer.codeJava();
javaProgrammer.eat();
javaProgrammer.work();
javaProgrammer.sleep();
}
}
开放/封闭原则
1.定义人类接口
人类都具有吃饭、睡觉的行为
csharp
public interface Human {
/**
* 吃饭
*/
void eat();
/**
* 睡觉
*/
void sleep();
}
2.学生实现人类接口
学生都具有学习的行为
csharp
public class Student implements Human {
@Override
public void eat() {
System.out.println("学生在吃饭");
}
@Override
public void sleep() {
System.out.println("学生在睡觉");
}
public void study() {
System.out.println("学生在学习");
}
}
3.增加高中生
满足开闭原则,增加高中生,但不修改学生类。
csharp
public class HighSchoolStudent extends Student {
@Override
public void eat() {
System.out.println("高中生在吃饭");
}
@Override
public void sleep() {
System.out.println("高中生在睡觉");
}
@Override
public void study() {
System.out.println("高中生在学习");
}
/**
* 扩展高中生独有的属性或行为
*/
public void doSomeThing() {
System.out.println("高中生在谈恋爱");
}
}
4.测试
ini
public class Test {
public static void main(String[] args) {
Student student = new Student();
student.eat();
student.sleep();
student.study();
// 不修改学生类(对修改关闭),增加高中生(对扩展开发)
HighSchoolStudent highSchoolStudent = new HighSchoolStudent();
highSchoolStudent.eat();
highSchoolStudent.sleep();
highSchoolStudent.study();
highSchoolStudent.doSomeThing();
}
}
里氏替换原则
1.定义老鼠类
csharp
public class Mouse {
void burrow() {
System.out.println("老鼠会打洞。。。");
}
}
2.定义仓鼠类继承老鼠
scala
public class Hamster extends Mouse {
// 子类可以不修改父类的方法,只是继承并使用 (老鼠天生会打洞)
}
3.定义玩具鼠类继承老鼠
scala
public class ToyMouse extends Mouse {
@Override
void burrow() {
// 它可以覆盖 burrow 方法,但不应该修改已经存在的行为
System.out.println("我是玩具鼠,我不会打洞,我会上天");
}
}
4.测试
java
public class Test {
public static void main(String[] args) {
Hamster hamster = new Hamster();
// 老鼠生的会打洞
hamster.burrow();
ToyMouse toyMouse = new ToyMouse();
// 老鼠生的不会打洞,会上天,就违背了该原则
toyMouse.burrow();
}
}
接口隔离原则
1.定义人类接口
kotlin
public interface Human {}
2.人类行为拆分接口,进行接口隔离
吃饭
csharp
public interface EatAction extends Human {
void eat();
}
睡觉
csharp
public interface SleepAction extends Human {
void sleep();
}
3.学生具备吃饭、睡觉的行为
typescript
public class Student implements EatAction, SleepAction {
@Override
public void eat() {
System.out.println("学生在吃饭");
}
@Override
public void sleep() {
System.out.println("学生在睡觉");
}
}
4.测试
typescript
public class Test {
public static void main(String[] args) {
Student student = new Student();
student.eat();
student.sleep();
}
}
依赖倒置原则
1.定义人类接口
人类都具有吃饭、睡觉的行为
csharp
public interface Human {
/**
* 吃饭
*/
void eat();
/**
* 睡觉
*/
void sleep();
}
2.定义程序员抽象类
csharp
public abstract class Programmer implements Human {
@Override
public void eat() {
System.out.println("程序员在吃饭");
}
@Override
public void sleep() {
System.out.println("程序员在睡觉");
}
/**
* 程序员都需要工作
*/
abstract void work();
}
定义Java程序员、测试程序员
Java程序员
csharp
public class JavaProgrammer extends Programmer {
@Override
public void eat() {
System.out.println("Java程序员在吃饭");
}
@Override
public void sleep() {
System.out.println("Java程序员在睡觉");
}
@Override
void work() {
System.out.println("Java程序员在工作");
}
}
测试程序员
csharp
public class TestProgrammer extends Programmer {
@Override
public void eat() {
System.out.println("测试程序员在吃饭");
}
@Override
public void sleep() {
System.out.println("测试程序员在睡觉");
}
@Override
void work() {
System.out.println("测试程序员在工作");
}
}
4.测试
ini
public class Test {
public static void main(String[] args) {
JavaProgrammer javaProgrammer = new JavaProgrammer();
javaProgrammer.eat();
javaProgrammer.work();
javaProgrammer.sleep();
TestProgrammer testProgrammer = new TestProgrammer();
testProgrammer.work();
}
}
迪米特法则
1.定义人类接口
kotlin
public interface Human {}
2.定义管理层接口并实现
java
public interface Manager extends Human {}
公司老板
typescript
public class Boss implements Manager {
public void meet(TeamLeader teamLeader) {
System.out.println("老板开会,发布任务");
teamLeader.assignTasks();
}
}
团队领导
typescript
public class TeamLeader implements Manager {
private Programmer programmer;
public void setProgrammer(Programmer programmer) {
this.programmer = programmer;
}
public void assignTasks() {
System.out.println("团队领导给研发分配任务");
this.programmer.work();
}
}
3.定义程序员接口并实现
csharp
public abstract class Programmer implements Human {
/**
* 程序员都需要工作
*/
abstract void work();
}
Java程序员
scala
public class JavaProgrammer extends Programmer {
@Override
void work() {
System.out.println("Java程序员完成Java代码开发");
}
}
4.测试
java
public class Test {
public static void main(String[] args) {
// 老板准备发布任务
Boss boss = new Boss();
// 找到项目经理
TeamLeader teamLeader = new TeamLeader();
// 项目经理拉上手底下研发
JavaProgrammer javaProgrammer = new JavaProgrammer();
teamLeader.setProgrammer(javaProgrammer);
// 老板发布任务
boss.meet(teamLeader);
}
}
合成复用原则
1.定义汽车引擎
csharp
public class Engine {
void start() {
System.out.println("发动机正在启动");
}
}
2.定义汽车
csharp
public class Car {
private Engine engine;
Car(Engine engine) {
this.engine = engine;
}
void start() {
engine.start();
System.out.println("汽车正在启动");
}
}
3.测试
java
public class Test {
public static void main(String[] args) {
// 在传统的继承方式下,可能会让Car继承自Engine,但这样的设计可能导致不必要的耦合,违反了合成复用原则。
Engine engine = new Engine();
// 使用合成复用原则通过组合来实现复用。
Car car = new Car(engine);
car.start();
}
}