七大设计模式原则

news/2024/7/5 2:58:36

1、开闭原则(Open-closed Principle)

开闭原则,是面向设计中最基础的设计原则。
一个软件实体类、模块、函数应该对扩展开放、对修改关闭
强调的是用抽象构建框架,用实现扩展细节。可以提高软件系统的可复用性和可维护性。

实例:

public interface ICourse {

    Integer getId();

    String getName();

    Double getPrice();

}
public class JavaCourse implements ICourse{

    private Integer id;

    private String name;

    private Double price;

    public Integer getId() {
        return this.id;
    }

    public String getName() {
        return this.name;
    }

    public Double getPrice() {
        return this.price;
    }

    public JavaCourse(Integer id, String name, Double price) {
        this.id = id;
        this.name = name;
        this.price = price;
    }
}
public class JavaDiscountCourse extends JavaCourse {

    public JavaDiscountCourse(Integer id, String name, Double price) {
        super(id, name, price);
    }

    public Double getOriginPrice() {
        return super.getPrice();
    }

    public Double getPrice() {
        return super.getPrice() * 0.6;
    }

}

2、本末倒置原则(Dependence Inversion Principle)

高层模块不应该依赖底层模块,二者都应该依赖其抽象。
抽象不应该依赖细节,细节应该依赖抽象。
本末倒置可以减少类与类之间的耦合性,提高系统的稳定性,提高代码的可读性和可维护性,降低修改程序造成的风险。

实例:

public interface ICourse {

    void study();

}
public class JavaCourse implements ICourse{

    @Override
    public void study() {
        System.out.println("学习Java");
    }

}
public class PythonCourse implements ICourse{

    @Override
    public void study() {
        System.out.println("学习Python");
    }

}
/**
 * 方式一:依赖注入,每次学习一个新课程就多创建一个类
 */
public class PersonOne {

    public void study(ICourse iCourse){
        iCourse.study();
    }

    public static void main(String[] args) {
        PersonOne personOne = new PersonOne();
        personOne.study(new JavaCourse());
        personOne.study(new PythonCourse());
    }
}
/**
 * 方式二:构造器注入,调用时每次都要创建实例
 */
public class PersonTwo {

    private ICourse iCourse;

    public PersonTwo(ICourse iCourse) {
        this.iCourse = iCourse;
    }

    public void study() {
        iCourse.study();
    }

    public static void main(String[] args) {
        PersonTwo personTwo = new PersonTwo(new JavaCourse());
        personTwo.study();
    }
}
/**
 * 方式三:Setter方式注入
 */
public class PersonThree {

    private ICourse iCourse;

    public void setCourse(ICourse iCourse) {
        this.iCourse = iCourse;
    }

    public void study() {
        iCourse.study();
    }

    public static void main(String[] args) {
        PersonThree personTwo = new PersonThree();
        personTwo.setCourse(new JavaCourse());
        personTwo.study();
    }
}

3、单一职责(Simple Responsibility Principle)

不要存在多于一个导致类变更的原因
一个对象应该只包含单一的职责,并且该职责被完整地封装在一个类中。

/**
 * course存在两种处理逻辑,这个地方修改代码
 */
public class Course {
    public void study(String name){
        if("直播".equals(name)){
            System.out.println("不能快进");
        }else {
            System.out.println("2xx倍速");
        }
    }

    public static void main(String[] args) {
        Course course = new Course();
        course.study("直播");
    }

}

修改下的代码,这样把两个课程给分开控制。

public class LiveCourse {
    public void study(String name){
        System.out.println("不能快进");
    }
}
public class ReplayCourse {
    public void study(String name){
        System.out.println("2xx倍速");
    }
}
public class Test {

    public static void main(String[] args) {
        LiveCourse liveCourse = new LiveCourse();
        liveCourse.study("直播");

        ReplayCourse replayCourse = new ReplayCourse();
        replayCourse.study("测试");
    }

}`在这里插入代码片`

4、接口隔离原则(Interface Segregation Principle)

用多个专门的接口,而不使用单一的接口,客户端不应该依赖它不需要的接口

  • 一个类对一类的依赖应该建立在最小的接口上
  • 建立单一接口,不要建立庞大的接口
  • 尽量细化接口,接口中的方法尽量少

实例:

public interface Animal {
    void eat();
    
    void fly();
    
    void swimming();
}
public class Bird implements Animal{
    @Override
    public void eat() {

    }

    @Override
    public void fly() {

    }

    @Override
    public void swimming() {

    }
}
public class Dag implements Animal{
    @Override
    public void eat() {

    }

    @Override
    public void fly() {

    }

    @Override
    public void swimming() {

    }
}

当dog不能飞,鸟儿不能游泳的时候,这个方法就会空,这时候需要根据动物行为设计不同的接口

public interface EatAnimal {

    void eat();

}
public interface FlyAnimal {

    void fly();

}
public interface SwimmingAnimal {

    void swimming();

}
public class Dog implements SwimmingAnimal, EatAnimal{
    @Override
    public void eat() {

    }

    @Override
    public void swimming() {

    }
}

5、迪米特法则(Law of demeter LoD)

一个对象应该对其他对象保持最少的了解。只和朋友交流,不喝陌生人说话。
出现在成员变量、方法的输入、输出参数中的类都可以称为成员朋友类,出现在方法体内内部的类不属于朋友类。

实例:

public class Course {
}
public class Employee {
    public void checkNumOfCourse(List<Course> courseList) {
        System.out.println("课程数量" + courseList.size());
    }
}
public class Leader {

    public void CommandCheckNumber(Employee employee){
        List<Course> courseList = new ArrayList<Course>();
        for (int i = 0; i < 20; i++) {
            courseList.add(new Course());
        }
        employee.checkNumOfCourse(courseList);
    }

    public static void main(String[] args) {
        Leader leader = new Leader();
        Employee employee = new Employee();
        leader.CommandCheckNumber(employee);
    }
}

根据迪米特法则,Leader只想要结果,不需要和Course有直接的接触,所以这个地方修改

public class EmployeeCp {
    public void checkNumOfCourse() {
        List<Course> courseList = new ArrayList<Course>();
        for (int i = 0; i < 20; i++) {
            courseList.add(new Course());
        }
        System.out.println("课程数量" + courseList.size());
    }
}
public class LeaderCp {

    public void CommandCheckNumber(EmployeeCp employee){
        employee.checkNumOfCourse();
    }

    public static void main(String[] args) {
        LeaderCp leader = new LeaderCp();
        EmployeeCp employee = new EmployeeCp();
        leader.CommandCheckNumber(employee);
    }
}

6、里氏替换原则(Liskov Substitution Priciple)

如果针对一个类型为T1的对象O1,都有类型T2的对象O2,使得以T1定义的所有程序P在所有的对象O1都替换成O2时,程序P的行为没有发生变化,那么类型T2还是类型T1的子类型。
1)子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法
2)子类仲可以增加自己特有的方法
3)当子类的方法重载父类的方法时,方法的前置条件(入参)要比父类方法的输入参数更宽松
4)当子类的方法实现
父类的方法时,方法的后置条件(输出/返回值)要比父类更严格或相等

优点:
1)约束继承泛滥,开闭原则的一种体现
2)加签程序的健壮性,同时变更也可以做到好的兼容,提高程序的维护性、扩展性,降低需求变更时的风险

实例:

public class Rectangle {

    private Long height;
    private Long width;

    public Long getHeight() {
        return height;
    }

    public Long getWidth() {
        return width;
    }

    public void setHeight(Long height) {
        this.height = height;
    }

    public void setWidth(Long width) {
        this.width = width;
    }
}
public class Square extends Rectangle {

    private Long length;

    public Long getLength() {
        return length;
    }

    public void setLength(Long length) {
        this.length = length;
    }

    @Override
    public Long getHeight() {
        return getLength();
    }

    @Override
    public void setHeight(Long height) {
        setLength(height);
    }

    @Override
    public Long getWidth() {
        return getLength();
    }

    @Override
    public void setWidth(Long width) {
        setLength(width);
    }

}
public class Test {
    public static void resize(Rectangle rectangle){
        while (rectangle.getWidth() >= rectangle.getHeight()){
            rectangle.setHeight(rectangle.getHeight()+1);
            System.out.printf("width: %s, height:%s", rectangle.getWidth(), rectangle.getHeight());
        }
        System.out.printf("width: %s, height:%s", rectangle.getWidth(), rectangle.getHeight());
    }

    public static void main(String[] args) {
        Rectangle rectangle = new Rectangle();
        rectangle.setWidth(20L);
        rectangle.setHeight(10L);
        resize(rectangle);

		//死循环
        Square square = new Square();
        square.setLength(10L);
        resize(square);
    }
}

当是正方形的时候,陷入死循环,违背里氏替换原则,父类替换成子类后结果不是预期。
修改代码,创建一个抽象四边形

public interface QuadRectangle {
    Long getWidth();

    Long getHeight();
}
public class RectangleCp implements QuadRectangle{

    private Long height;
    private Long width;

    public Long getHeight() {
        return height;
    }

    public Long getWidth() {
        return width;
    }

    public void setHeight(Long height) {
        this.height = height;
    }

    public void setWidth(Long width) {
        this.width = width;
    }
}
public class SquareCp implements QuadRectangle {

    private Long length;

    public Long getLength() {
        return length;
    }

    public void setLength(Long length) {
        this.length = length;
    }

    @Override
    public Long getHeight() {
        return getLength();
    }

    @Override
    public Long getWidth() {
        return getLength();
    }

}

7、合成复用原则(Composite Reuse Principle)

尽量使用对象组合(has-a)/聚合(contain-a),而不是继承达到软件复用的目的。
继承叫做“白箱复用”,把所有的实现细节暴露给子类
组合/聚合称为“黑箱复用”,对类以外的对象是无法获取到实现细节的

实例:

public class DBConnection {
    public String getConnection() {
        return "MySql连接";
    }
}
public class ProductDao {

    private DBConnection dbConnection;

    public void setDbConnection(DBConnection dbConnection){
        this.dbConnection = dbConnection;
    }

    public void addProduct(){
        String conn = dbConnection.getConnection();
        System.out.println("创建商品");
    }

}

如果这时候不只是mysql还有其他类型的数据库,违反开闭原则
修改代码:

public abstract class DBConnectionCp {
    public abstract String getConnection();
}
public class MysqlConnection extends DBConnection{
    @Override
    public String getConnection() {
        return "mysql";
    }
}
public class OracleConnection extends DBConnection{
    @Override
    public String getConnection() {
        return "Oracle";
    }
}

http://lihuaxi.xjx100.cn/news/1372160.html

相关文章

Promise基础

Promise对象 Promise概念 Promise 对象表示异步操作最终的完成&#xff08;或失败&#xff09;以及其结果值。 一个 Promise 是一个代理&#xff0c;它代表一个在创建 promise 时不一定已知的值。它允许你将处理程序与异步操作的最终成功值或失败原因关联起来。这使得异步方…

能耗监测管理系统

能耗监测管理系统是一种用于监测和管理能源消耗的软件系统&#xff0c;可以帮助企业、机构或个人实现对能源消耗的实时监控、分析和管理。随着能源问题的日益凸显&#xff0c;能耗监测管理系统的重要性也越来越受到人们的关注。本文将从以下几个方面介绍能耗监测管理系统。 一、…

Delta 表定时Compact设计

Delta 表定时Compact设计 目前我们的数仓中delta表实时跟离线的都有&#xff0c;离线的表主要是每天的定时任务的运行&#xff0c;并根据日期字段进行分区的存储。离线任务正常是读取前一天的数据计算&#xff0c;并写入当天的时间分区&#xff0c;或者是重跑数据&#xff0c;…

[leetcode]2365. Task Scheduler II

链接&#xff1a;力扣 给你一个下标从 0 开始的正整数数组 tasks &#xff0c;表示需要 按顺序 完成的任务&#xff0c;其中 tasks[i] 表示第 i 件任务的 类型 。 同时给你一个正整数 space &#xff0c;表示一个任务完成 后 &#xff0c;另一个 相同 类型任务完成前需要间隔…

华纳云:Linux系统的SVN服务器怎么安装配置

在Linux系统上搭建SVN服务器&#xff0c;可以使用Apache HTTP Server作为SVN的前端服务器&#xff0c;并安装Subversion软件包用于管理版本库。下面是安装配置SVN服务器的基本步骤&#xff08;以Ubuntu为例&#xff09;&#xff1a; 安装Apache HTTP Server和Subversion&#…

TCP实现原理和为什么需要三次握手?两次握手不可以?四次握手不可以?

TCP实现原理和为什么需要三次握手?两次握手不可以?四次握手不可以? 1. 什么是TCP协议? TCP&#xff1a;Transmission Control Protocol翻译过来就是传输控制协议,TCP协议是一个面向连接的、可靠的、基于字节流的传输层协议RFC 793对TCP连接的定义 > Connections: >…

创作纪念日——Hello World

创作纪念日——Hello World 导读 正在报告&#xff01; ——迅捷斥候 成就 精通多种语言的Hello World 1. C #include int main() {printf("Hello, World");return(0); }2. C int main() {std::cout << "Hello World";return 0; }3. C# using…

mysql 使用JSON_EXTRACT提取 json数据格式的字段

task 表中有如下数据结构 iddata_ext1{“name”: “张三”,“gender”: 1,“age”: 20} 提取data_ext字段 select id,cast(JSON_UNQUOTE(JSON_EXTRACT(data_ext, $.name)) as char) as name,cast(JSON_UNQUOTE(JSON_EXTRACT(data_ext, $.gender)) as char) as gender, cast(…