欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

开闭原则

程序员文章站 2022-03-15 15:36:32
...

前言

做事情要务实,万丈高楼平地起,底层基础决定上层建筑,那么在你阅读一些源码前有一些知识就很有必要去掌握,打个比方来说就拿Spring源码里面运动了大量的设计模式,那么设计模式是怎么来的?说直白点就是在某些特定场景下解决该类方法的一个模板,前人总结的经验教训!在学习设计模式前我们很有必要去了解下设计模式所需要遵守的规则(无规矩不成方圆,想要创新可以,但是请先自己对当前所学知识有一个全新的认知以后再去创新吧),本文是笔者学习完之后根据自己的理解进行整理,建议大家学习完视频也好,看书也罢一定要进行知识的总结

开闭原则

定义: 对修改关闭对扩展开放

我的理解: 指对已经写好的代码尽量不要去改动它!尽可量的在此基础之上进行封装,因为你永远也不知道别人写的代码到底有多少坑在里面!!! 切记切记,这个坑在我踩过一次之后真的是怕了,这一条要理解核心!!! 别碰已经写好的代码,尽量在它基础之上进行拓展

场景如下: 我们现在正在做一个活动,我是卖车的,现在就针对奥迪A8这一款车进行8折处理,我们来进行一点点拆分

不遵守的情况,所带来的麻烦

需要定义的类:

  • a. 我们有很多车所以需要定一个车的公有类
  • b. 我们需要去定义实现类去继承我们当前的类

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Car {
    /**
     *  汽车名称
     */
    private String name;
    /**
     * 汽车价格
     * 开发的小技巧,如果说这个数值需要做持久化存储
     * eg:存储到数据库那么数据库里面存储的是单位: 分
     * 那么我们这里面定义的就是int/Integer类型,这样子在存储到数据库里面
     * 以及进行后端数据操作的时候会省下很多力气,因为存储到后端如果存储金钱的话,可能要应道BigDecimal或Double
     * 如果我们存储的是分,在从数据库拿出来之后只需要进行: 数值/100那么接下来的操作都会很容易,涉及到的数值计算,数值转换
     * 都会变得很容易,啰嗦一句
     * 
     */
    private Double price;
    /**
     * 汽车颜色
     */
    private String color;
}


Audi类


public class Audi extends Car{

    @Override
    public String getName() {

        return "奥迪";
    }

    @Override
    public Double getPrice() {

        return 2000.0;
    }

    @Override
    public String getColor() {

        return "白色";
    }
    
    @Override
    public String toString() {

        return "name  : " + this.getName() +  "\n" +
                "price : " + this.getPrice() + "\n" +
                "color : " + this.getColor() + "\n";

    }
}

宝马类


public class Bmw extends Car{

    @Override
    public String getName() {

        return "宝马三系";
    }

    @Override
    public Double getPrice() {
        return 1000.0;
    }

    @Override
    public String getColor() {

        return "白色";
    }
    
    @Override
    public String toString() {

        return "name  : " + this.getName() +  "\n" +
                "price : " + this.getPrice() + "\n" +
                "color : " + this.getColor() + "\n";

    }
}

第一次测试,我们仅仅需要把当前类的属性打印出来


public class CarTest {

    public static void main(String[] args) {

        Car audi = new Audi();

        Car bmw = new Bmw();

        System.out.println(audi);

        System.out.println(bmw);
    }
}

开闭原则

下面我们提出一个疑问,如果我们想要给奥迪这款车八折出售,那么就会出现一个问题,我们是不是要动以前的代码,是这个样子的,在日常开发中可不是这种你一个对象只被你自己用,很可能其他对象也有调用这个方法

开闭原则

那我下面在提出一个疑问我想要给奥迪车打八折,打印其价格,并且将Audi+Bmw折后价与折前价的差价打印出来

那么下面去讨论一个问题:

  • 实现的方法: 一般的理解是,我们可以做一个中间变量,去存储Audi * 0.8的价格,这样做可以实现,没问题!但是你这样子要去动原有的代码对么?计算综合传递的对象如下:

    public static double calcPrice(Audi audi,Bmw bmw) {

        return audi.getPrice() + bmw.getPrice();

    }

这里传递的是对象,不是具体的数值(容错性高),这里就出现问题了,再提个奇葩的需求,我想看看Audi+Bmw的混合色。。。

最好的办法就是在不变原有的代码的基础之上对其封装,我们都知道子类拥有父类的资产!当我们调用子父类都有的方法的时候,首先会调用子类,子类没有再去调用父类的,因此如下:


public class AudiDiscount extends Audi{

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

    @Override
    public Double getPrice() {
        return super.getPrice() * 0.8;
    }

    @Override
    public String getColor() {
        return super.getColor();
    }

    @Override
    public String toString() {
        return super.toString();
    }
}

最终测试类:


public class CarTest {

    public static void main(String[] args) {

        Audi audi = new Audi();

        Bmw bmw = new Bmw();

        System.out.println(audi);

        System.out.println(bmw);

        System.out.println("两辆车的原价为: " + calcPrice(audi,bmw));

        System.out.println("\n--- 我想要给奥迪车打八折,打印其价格,并且将Audi+Bmw折后价与折前价的差价打印出来 ---\n");

        Audi audi8 = new AudiDiscount();

        System.out.println("两辆车的折后总价为: " + calcPrice(audi8,bmw));

        System.out.println("奥迪车8折之后的价格为: " + audi8.getPrice() + ", 打折前后的差价为: "
                                                  + (calcPrice(audi,bmw) - calcPrice(audi8,bmw)));

    }


    public static double calcPrice(Audi audi,Bmw bmw) {

        return audi.getPrice() + bmw.getPrice();

    }
}

输出结果

开闭原则

ps: 不要在意最上层的Car类用不用接口实现,要注重这个思想,想要接口实现的自己去改造