天天看点

厚积薄发打卡Day113:Debug设计模式:设计原则(一)<开闭原则、依赖倒置、单一职责>厚积薄发打卡Day113:Debug设计模式:设计原则(一)<开闭原则、依赖倒置、单一职责>开闭原则依赖倒置单一职责

厚积薄发打卡Day113:Debug设计模式:设计原则(一)<开闭原则、依赖倒置、单一职责>

开闭原则

定义

一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。其优点:提高软件系统的可复用性及可维护性

用抽象构建框架,用实现扩展细节,实现 面向抽象编程。

中心思想:抽象构建框架,实现扩展细节

场景举例Coding

在线课程购买例子,课程在线购买:

厚积薄发打卡Day113:Debug设计模式:设计原则(一)<开闭原则、依赖倒置、单一职责>厚积薄发打卡Day113:Debug设计模式:设计原则(一)&lt;开闭原则、依赖倒置、单一职责&gt;开闭原则依赖倒置单一职责
/**
 * 课程接口
 */
public interface ICourse {
    // 课程id
    Integer getId();

    // 课程名字
    String getName();

    // 课程价格
    Double getPrice();
}
           
/**
 * Java课程
 */
public class JavaCourse implements ICourse {
    private Integer Id;
    private String name;
    private Double price;

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

    @Override
    public Integer getId() {
        return this.Id;
    }

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

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

测试类:

public class Test {
    public static void main(String[] args) {
        ICourse course = new JavaCourse(1415, "Java企业级别开发", 299d);
        System.out.printf("课程id: %d,课程名称:%s,课程价格:%f 元\n", course.getId(), course.getName(), course.getPrice());
    }
}
           
课程id: 1415,课程名称:Java企业级别开发,课程价格:299.000000 元
           

场景变更:现在遇到活动,线上课程通通八折!那应该怎么修改呢?

~~修改接口?~~那会影响全部实现类,如果有一个实现类则修改一个实现类,那如果实现类很多是否都需要一个个进行修改呢?

**软件开发设计重点:接口不应该轻易修改,稳定且可靠,作为契约。**同时,越底层的模块变化影响越大,越高层的模块变化影响则越小。

那不在影响原有代码的基础上进行扩展,最好的方法就是使用Java的多态特性:继承。

场景实现:

厚积薄发打卡Day113:Debug设计模式:设计原则(一)<开闭原则、依赖倒置、单一职责>厚积薄发打卡Day113:Debug设计模式:设计原则(一)&lt;开闭原则、依赖倒置、单一职责&gt;开闭原则依赖倒置单一职责
public class DiscountCourse extends JavaCourse {
    public DiscountCourse(Integer id, String name, Double price) {
        super(id, name, price);
    }

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


    public Double getDiscountPrice() {
        // 同时这里可以对折扣价格方案进行处理
        return super.getPrice() * 0.8;
    }
}
           

测试类:

public class Test {
    public static void main(String[] args) {
        ICourse course = new JavaCourse(1415, "Java企业级别开发", 299d);
        System.out.printf("课程id: %d,课程名称:%s,课程价格:%f 元\n", course.getId(), course.getName(), course.getPrice());

        DiscountCourse course2 = new DiscountCourse(1415, "Java企业级别开发", 299d);
        System.out.printf("课程id: %d,课程名称:%s,课程原始价格:%f 元,618活动折扣价为:%f 元\n", course2.getId(), course2.getName(), course2.getOriginPrice(), course2.getDiscountPrice());
    }
}
           
课程id: 1415,课程名称:Java企业级别开发,课程价格:299.000000 元
课程id: 1415,课程名称:Java企业级别开发,课程原始价格:299.000000 元,618活动折扣价为:239.200000 元
           

这样通过继承的方式,不改变原有代码的基础上,实现了折扣价方案的修改实现。

依赖倒置

定义:

  • 高层模块不应该依赖低层模块,二者都应该依赖其抽象。
  • 抽象不应该依赖细节;细节应该依赖抽象
  • 核心思想:针对接口编程,面向接口编程,不要针对实现编程

优点:

  • 可以减少类间的耦合性、提高系统稳定性,提高代码可读性和可维护性,可降低修改程序所造成的风险

场景Coding:

  • 举例:面向实现类编程
    public class Wayne {
        public void studyJavaCourse(){
            System.out.println("Wayne在学习Java课程");
        }
        public void studyPythonCourse(){
            System.out.println("Wayne在学习Python课程");
        }
    }
               
    public class Test {
        public static void main(String[] args) {
            // v1
            Wayne wayne = new Wayne();
            wayne.studyJavaCourse();
            wayne.studyPythonCourse();
        }
    }
               
    Wayne在学习Java课程
    Wayne在学习Python课程
               
    • 此时Test是应用层,Wayne是底层模块,如果这时候wayne要学习更多课程,则在底层模块进行修改,违背了

      高层模块不应该依赖低层模块

      ,直接引用了而不是通过抽象依赖。
  • 引用抽象
    厚积薄发打卡Day113:Debug设计模式:设计原则(一)<开闭原则、依赖倒置、单一职责>厚积薄发打卡Day113:Debug设计模式:设计原则(一)&lt;开闭原则、依赖倒置、单一职责&gt;开闭原则依赖倒置单一职责
    // 抽象依赖
    public interface IStudy {
        void studyCourse();
    }
               
    依赖实现:
    public class GoStudy implements IStudy {
        @Override
        public void studyCourse() {
            System.out.println("Wayne在学习Go语言");
        }
    }
               
    public class JavaStudy implements IStudy{
        @Override
        public void studyCourse() {
            System.out.println("Wayne在学习Java");
        }
    }
               
    public class PythonStudy implements IStudy {
        @Override
        public void studyCourse() {
            System.out.println("Wayne在学习Python");
        }
    }
               
    底层:
    public class Wayne {
        public void studyCourse(IStudy study) {
            study.studyCourse();
        }
    }
               
    应用层:
    public class Test {
        public static void main(String[] args) {
            //v2
            Wayne wayne = new Wayne();
            wayne.studyCourse(new PythonStudy());
            wayne.studyCourse(new JavaStudy());
            wayne.studyCourse(new GoStudy());
        }
    }
               
    Wayne在学习Python
    Wayne在学习Java
    Wayne在学习Go语言
               
  • 使用构造器注入(单例模式):有点Spring的味道了
public class Wayne {
    // ---单例:
    private IStudy iStudy;

    public Wayne(IStudy iStudy) {
        this.iStudy = iStudy;
    }

    public void studyCourse() {
        iStudy.studyCourse();
    }
}
           
//v3:单例模式:
new Wayne(new JavaStudy()).studyCourse();
new Wayne(new PythonStudy()).studyCourse();
           
  • set方法注入:注入方式无需修改底层模块,即后续想要学习什么课程直接扩展IStudy即可。
    public class Wayne {
        // set注入
        private IStudy iStudy;
    
        public void setiStudy(IStudy iStudy) {
            this.iStudy = iStudy;
        }
        public void studyCourse() {
            iStudy.studyCourse();
        }
    }
               
    //v4:set注入
        Wayne wayne = new Wayne();
        wayne.setiStudy(new JavaStudy());
        wayne.studyCourse();
    
        wayne.setiStudy(new GoStudy());
        wayne.studyCourse();
               
    综上总结:面向接口编程

单一职责

定义:

不要存在多于一个导致类变更的原因,一个类/接口/方法只负责一项职责

优点:降低类的复杂度、提高类的可读性,提高系统的可维护性、降低变更引起的风险

场景Coding

  • 场景耦合
    public class Bird {
        public void mainMoveMode(String birdName) {
            //使用边界判断
            if ("鸵鸟".equals(birdName)) {
                System.out.println(birdName + "用脚走");
            } else {
                System.out.println(birdName + "用翅膀飞");
            }
        }
    }
               
    public class Test {
        public static void main(String[] args) {
            Bird bird = new Bird();
            bird.mainMoveMode("鸵鸟");
            bird.mainMoveMode("大雁");
            bird.mainMoveMode("鸽子🕊");
        }
    }
               
    鸵鸟用脚走
    大雁用翅膀飞
    鸽子🕊用翅膀飞
               
    如果后面增加飞行动物,则需要不断修改Bird里面的代码,同时功能并不单一,违背单一职责原则。
  • 类扩展,实现单一原则
厚积薄发打卡Day113:Debug设计模式:设计原则(一)<开闭原则、依赖倒置、单一职责>厚积薄发打卡Day113:Debug设计模式:设计原则(一)&lt;开闭原则、依赖倒置、单一职责&gt;开闭原则依赖倒置单一职责
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) {
        WalkBird walkBird = new WalkBird();
        walkBird.mainMoveMode("鸵鸟");

        FlyBird flyBird = new FlyBird();
        flyBird.mainMoveMode("大雁");
    }
}
           
鸵鸟用脚走
大雁用翅膀飞
           
  • 接口扩展,以课程举例
    public interface ICourse {
        // 课程内容管理
        String getCourseName();
        byte[] getCourseVideo();
    
        // 课程中心管理
        void studyCourse();
        void refundCourse();
    }
               
    接口在实现类中进行细分:
厚积薄发打卡Day113:Debug设计模式:设计原则(一)<开闭原则、依赖倒置、单一职责>厚积薄发打卡Day113:Debug设计模式:设计原则(一)&lt;开闭原则、依赖倒置、单一职责&gt;开闭原则依赖倒置单一职责
public interface ICourseContent {
    String getCourseName();
    byte[] getCourseVideo();
}
           
public interface ICourseManager {
    void studyCourse();
    void refundCourse();
}
           
public class CourseImpl implements ICourseManager, ICourseContent {
    @Override
    public void studyCourse() {
    }

    @Override
    public void refundCourse() {
    }

    @Override
    public String getCourseName() {
        return null;
    }

    @Override
    public byte[] getCourseVideo() {
        return new byte[0];
    }
}
           
  • 方法级别,单一职责,方法一般通过对象实现,酌情参考。
    public class Method {
        private void updateUserInfo(String userName, String address) {
            userName = "wayne";
            address = "beijing";
        }
    
        private void updateUserInfo(String userName, String... properties) {
            userName = "wayne";
    //        address = "beijing";
        }
    
        private void updateUsername(String userName) {
            userName = "wayne";
        }
    
        private void updateUserAddress(String address) {
            address = "beijing";
        }
    
        private void updateUserInfo(String userName, String address, boolean bool) {
            if (bool) {
                //todo something1
            } else {
                //todo something2
            }
            userName = "wayne";
            address = "beijing";
        }
    }
               

总结:单一职责会新增很多类,若盲目使用则会造成类爆炸要根据实际情况,尽量做到接口和方法的单一职责