001-从零学习设计模式-设计原则

写在最前

文档地址:gitee.com/csps/mingyu...

设计模式

推荐浏览:软件设计模式

  • 代表了代码的最佳实践,被有经验的开发人员所使用;
  • 设计模式是很多被反复使用并知晓的,主要是对代码和经验的总结;
  • 使用设计模式是为了重用代码,让代码更容易被他人理解,保证代码的可靠性;
  • 对接口编程而不是对实现变成;
  • 有限使用对象组合而不是继承关系;

设计原则

设计模式的六大设计(第七点为后增)原则通常是指的面向对象设计原则,也被称为SOLID原则。这六大设计原则分别是:

  1. 单一职责原则(Single Responsibility Principle,SRP):

    • 一个类应该只有一个引起变化的原因。这意味着一个类应该只有一个责任,只关注一个功能领域;
    • 降低程序的复杂度,提高程序可维护性,降低了变更所带来的风险;
  2. 开放/封闭原则(Open/Closed Principle,OCP):

    • 软件实体(类、模块、函数等)应该是可扩展的,但不可修改的。即,对于新增功能应通过扩展而不是修改现有代码来实现;
    • 使用抽象进行构建,使用实现扩展细节,面向抽象编程;
    • 提高软件系统的可复用性和可维护性;
  3. 里氏替换原则(Liskov Substitution Principle,LSP):

    • 所有引用基类的地方必须能够透明地使用其子类的对象,即子类可以替代基类而不影响程序的正确性;
    • 里氏替换原则是继承复用的基石,对开闭原则的补充;
    • 子类可以实现父类的抽象方法,但是不能覆盖原有父类的方法,子类中可以增加自己特有的方法;
    • 可以增加程序的健壮性;
  4. 接口隔离原则(Interface Segregation Principle,ISP):

    • 一个类对于它的客户端应该只暴露它们需要的方法,而不应该强迫客户端使用它们不需要的方法。接口应该是客户端特定的,而不是通用的;
    • 尽量细化接口,接口中的方法尽量少;
    • 符合低耦合的设计思想,提高了可扩展性和可维护性;
  5. 依赖倒置原则(Dependency Inversion Principle,DIP):

    • 高层模块不应该依赖于低层模块,而是两者都应该依赖于抽象。抽象不应该依赖于具体实现,而具体实现应该依赖于抽象;
    • 依赖倒置原则是开闭原则的基础,针对接口进行编程;
    • 可以减少类之间的耦合行,提高系统稳定性,提高代码可读性和可维护性;
    • 降低修改程序所造成的风险;
  6. 迪米特法则(Law of Demeter,LoD):

    • 一个对象应该对其他对象有最少的了解,即一个对象不应该直接调用另一个对象内部的方法,而应该通过一些中介者来进行间接调用;
    • 为了降低类与类之间的耦合关系;
    • 强调只和朋友交流,不和陌生人说话。朋友指的是成员变量或方法中输入输出的参数;
  7. 合成复用原则(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();
    }
}
相关推荐
monkey_meng41 分钟前
【Rust中的迭代器】
开发语言·后端·rust
余衫马44 分钟前
Rust-Trait 特征编程
开发语言·后端·rust
monkey_meng1 小时前
【Rust中多线程同步机制】
开发语言·redis·后端·rust
paopaokaka_luck5 小时前
【360】基于springboot的志愿服务管理系统
java·spring boot·后端·spring·毕业设计
码农小旋风7 小时前
详解K8S--声明式API
后端
Peter_chq7 小时前
【操作系统】基于环形队列的生产消费模型
linux·c语言·开发语言·c++·后端
Yaml47 小时前
Spring Boot 与 Vue 共筑二手书籍交易卓越平台
java·spring boot·后端·mysql·spring·vue·二手书籍
小小小妮子~7 小时前
Spring Boot详解:从入门到精通
java·spring boot·后端
hong1616887 小时前
Spring Boot中实现多数据源连接和切换的方案
java·spring boot·后端
睡觉谁叫~~~8 小时前
一文解秘Rust如何与Java互操作
java·开发语言·后端·rust