JAVA和Nginx 教程大全

网站首页 > 精选教程 正文

软件设计七大原则,程序员标配(一)

wys521 2024-11-02 14:56:18 精选教程 24 ℃ 0 评论

更多java文章与项目资源、毕业设计、福利

关注公众号 程序猿forever


软件设计七大原则

  • 3-1 本章导航
  • 3-2 开闭原则讲解
  • 3-3 开闭原则coding
  • 3-4 依赖倒置原则讲解+coding
  • 3-5 单一职责原则讲解
  • 3-6 单一职责原则coding
  • 3-7 接口隔离原则讲解+coding
  • 3-8 迪米特法则讲解+coding
  • 3-9 里氏替换原则讲解
  • 3-10 里氏替换原则coding
  • 3-11 合成复用原则讲解+coding

  • 3-1 本章导航


    3-2 开闭原则讲解

    实现开闭原则的核心思想就是面向抽象编程而不是面向具体的实现编程。

    3-3 开闭原则coding

    1. 首先定义一个课程的接口:
    public interface ICourse {
        Integer getId();
        String getName();
        Double getPrice();
    }
    12345
    1. 定义一个Java课程的类并且实现课程接口:
    public class JavaCourse implements ICourse {
        private Integer id;
        private String name;
        private Double price;
    
        public JavaCourse(Integer id, String name, Double price) {
            this.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;
        }
    }
    1234567891011121314151617181920212223242526
    1. 定义一个Test测试类:
    public class Test {
        public static void main(String[]args){
            ICourse javaCourse = new JavaCourse(96, "Java 从零开始到企业级开发", 348d);
            System.out.println("课程Id:" + javaCourse.getId() + "课程名称:" + javaCourse.getName() + "课程价格:" + javaCourse.getPrice());
        }
    }
    123456

    输出结果如下:

    课程Id:96课程名称:Java 从零开始到企业级开发课程价格:348.0

    现在的类结构图如图所示:


    假如现在双十一的时候,要进行课程的打折活动:我们应该如何去做呢 ?
    我们可以这样来做:
    添加一个计算打折价格的方法:

    public interface ICourse {
        Integer getId();
        String getName();
        Double getPrice();
        Double getDiscountPrice();
    }
    123456

    同样实现类也要实现这个方法:

    public class JavaCourse implements ICourse {
        private Integer id;
        private String name;
        private Double price;
    
        public JavaCourse(Integer id, String name, Double price) {
            this.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;
        }
    
        @Override
        public Double getDiscountPrice() {
            return this.price*0.8;
        }
    }
    12345678910111213141516171819202122232425262728293031

    在Test类里面,我们就是可以这样来进行获取:

    public class Test {
        public static void main(String[]args){
            ICourse javaCourse = new JavaCourse(96, "Java 从零开始到企业级开发", 348d);
            System.out.println("课程Id:" + javaCourse.getId() + "课程名称:" + javaCourse.getName() + "课程价格:" + javaCourse.getPrice()+"双十一打折价格:"+javaCourse.getDiscountPrice());
        }
    }
    123456

    输出结果如下:

    课程Id:96课程名称:Java 从零开始到企业级开发课程价格:348.0双十一打折价格:278.40000000000003


    但是,这种方法不好,假如课程很多,那么所有的课程的实现类都要重写一下方法,接口应该是稳定的,不应该是经常修改的。


    我们再换一种方法:
    我们写一个Java课程打折类并且继承于Java课程类,之前的课程类里面的价格就不打折了:

    public class JavaDiscountCourse extends JavaCourse {
        public JavaDiscountCourse(Integer id, String name, Double price) {
            super(id, name, price);
        }
    
        @Override
        public Double getPrice() {
            return super.getPrice()*0.8;
        }
    }
    12345678910

    然后,我们在测试的时候,就是可以直接指向Java课程打折类的这个对象就可以了:

    public class Test {
        public static void main(String[]args){
            ICourse javaCourse = new JavaDiscountCourse(96, "Java 从零开始到企业级开发", 348d);
            System.out.println("课程Id:" + javaCourse.getId() + "课程名称:" + javaCourse.getName() + "课程价格:" + javaCourse.getPrice());
        }
    }
    123456

    这个时候的结果就是:这里有丢失精度的问题,可以使用String构造器的BigDecimal来解决

    课程Id:96课程名称:Java 从零开始到企业级开发课程价格:222.72000000000003


    如果我们还想要原价,我们可以这样来做:

    public class JavaDiscountCourse extends JavaCourse {
        public JavaDiscountCourse(Integer id, String name, Double price) {
            super(id, name, price);
        }
        /** 获取原价的方法 */
        public Double getOriginPrice() {
            return super.getPrice();
        }
        
        @Override
        public Double getPrice() {
            return super.getPrice()*0.8;
        }
    }
    1234567891011121314

    这个时候,我们就是可以这样来调用:

    public class Test {
        public static void main(String[]args){
            ICourse iCourse = new JavaDiscountCourse(96, "Java 从零开始到企业级开发", 348d);
            /** 如果调用实现类里面的方法,我们就必须要进行强转一下 */
            JavaDiscountCourse javaCourse = (JavaDiscountCourse)iCourse;
            System.out.println("课程Id:" + javaCourse.getId() + "课程名称:" + javaCourse.getName() + "课程价格:"+javaCourse.getOriginPrice()+"课程折后价格:" + javaCourse.getPrice());
        }
    }
    12345678

    执行结果如下:

    课程Id:96课程名称:Java 从零开始到企业级开发课程价格:348.0课程折后价格:278.40000000000003


    现在的类图如图所示:

    我们通过了继承了基类,然后对其进行扩展,对扩展是开发的,而对修改接口和基类是关闭的;
    越是基层的模块的修改影响的范围是越大的。

    3-4 依赖倒置原则讲解+coding

    依赖倒置原则的核心就是:面向接口编程


    有一个类:里面有两个方法,一个学习java课程的方法,一个是学习FE课程的方法:

    public class Tom {
        public void studyJavaCourse() {
            System.out.println("Tom在学习Java课程");
        }
        public void studyFECourse() {
            System.out.println("Tom在学习FE课程");
        }
    }
    12345678

    这个时候,我们写上一个测试类:

    public class Test {
        public static void main(String[]args){
            Tom tom = new Tom();
            tom.studyJavaCourse();
            tom.studyFECourse();
        }
    }
    1234567

    如果这个时候,我还想要添加一个学习Python课程的方法,这个时候,我可以在基类里面进行添加方法:

    public class Tom {
        public void studyJavaCourse() {
            System.out.println("Tom在学习Java课程");
        }
        public void studyFECourse() {
            System.out.println("Tom在学习FE课程");
        }
        public void studyPythonCourse() {
            System.out.println("Tom在学习Python课程");
        }
    }
    1234567891011

    以上我们的做法就是在面向实现来进行编程,面向实现类来进行编程的话, 扩展性比较的差,这个就是依赖于底层的实现的


    现在我们来引入抽象来解决这个问题:

  • 首先写上一个课程接口:
  • public interface ICourse {
        void studyCourse();
    }
    123
  • 有两个实现类:一个是学习Java的实现类,一个是学习前端的实现类,分别是:
  • public class JavaCourse implements ICourse {
        @Override
        public void studyCourse() {
            System.out.println("Tom在学习Java课程");
        }
    }
    123456
    public class FECourse implements ICourse {
        @Override
        public void studyCourse() {
            System.out.println("Tom在学习FE课程");
        }
    }
    123456

    原来的Tom类,我们就要进行重构了,写了一个学习课程的方法,传入了学习课程的接口,由具体的实现类来进行实现:
    具体学了哪些课程,是由具体的实现类来决定的:

    public class Tom {
        public void studyCourse(ICourse iCourse) {
            iCourse.studyCourse();
        }
    }
    12345

    我们对其进行测试:

    public class Test {
        public static void main(String[]args){
            Tom tom = new Tom();
            tom.studyCourse(new JavaCourse());
            tom.studyCourse(new FECourse());
        }
    }
    1234567

    执行结果为:

    Tom在学习Java课程
    Tom在学习FE课程



    这个时候,如果还要学习Python的课程的话,那我们就可以再写上一个实现类来对接口进行实现即可:

    public class PythonCourse implements ICourse {
        @Override
        public void studyCourse() {
            System.out.println("Tom在学习Python课程");
        }
    }
    123456

    我们就可以来调用了:

    public class Test {
        public static void main(String[]args){
            Tom tom = new Tom();
            tom.studyCourse(new JavaCourse());
            tom.studyCourse(new FECourse());
            tom.studyCourse(new PythonCourse());
        }
    }
    12345678

    输出结果:

    Tom在学习Java课程
    Tom在学习FE课程
    Tom在学习Python课程


    以上是通过接口方法的方式来注入具体的实现;
    当然,我们也可以通过构造器的方式来注入具体的实现:
    在Tom这个类里面写一个构造器,把接口作为Tom类里面的一个成员属性,然后通过构造器来对其进行赋值:

    public class Tom {
        private ICourse iCourse;
    
        public Tom(ICourse iCourse) {
            this.iCourse = iCourse;
        }
    	/** 这里的方法,就只需要调用类成员变量ICourse里面的studyCourse()方法就可以了 */
        public void studyCourse() {
            iCourse.studyCourse();
        }
    }
    1234567891011

    测试:

    public class Test {
        public static void main(String[]args){
            Tom tom = new Tom(new JavaCourse());
            tom.studyCourse();
        }
    }
    123456

    测试结果:

    Tom在学习Java课程


    以上的用构造器来进行传递接口的实现,也不是很好,每次学一个新的课程的时候,还有重新new一个类;
    这个时候,我们可以利用set方法来进行注入:

    public class Tom {
        private ICourse iCourse;
    
        public void setiCourse(ICourse iCourse) {
            this.iCourse = iCourse;
        }
    
        public void studyCourse() {
            iCourse.studyCourse();
        }
    }
    1234567891011

    这个时候,我们就是可以这样来用了:

    public class Test {
        public static void main(String[]args){
            Tom tom = new Tom();
            tom.setiCourse(new JavaCourse());
            tom.studyCourse();
    
            tom.setiCourse(new FECourse());
            tom.studyCourse();
        }
    }
    12345678910

    执行结果:

    Tom在学习Java课程
    Tom在学习FE课程


    现在的类图:

    本文暂时没有评论,来添加一个吧(●'◡'●)

    欢迎 发表评论:

    最近发表
    标签列表