Seven Principles of Software Design

https://github.com/rexllz/design

开闭原则(Open/Closed )

对扩展开放、对修改关闭

  • 提高软件的可复用和可维护性

  • 面向抽象编程

  • 面向接口编程

public interface ICourse {
    Integer getId();
    String getName();
    Double getPrice();
}
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;
    }

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

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

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

public class JavaDiscountCourse extends JavaCourse{

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

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

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

oc

依赖倒置原则(Dependency Inversion)

高层模块不应该依赖底层模块,二者都应该依赖抽象

  • 抽象不应该依赖细节,细节应该依赖抽象
  • 针对接口编程,不可针对实现编程

高层依赖底层的情况

public class Rex {
    public void studyJava(){
        System.out.println("study java");
    }
    public void studyPython(){
        System.out.println("study python");
    }
    public void studyJs(){
        System.out.println("study js");
    }
}
//v1 面向实现编程
//高层依赖底层
//test 依赖 rex
public static void main(String[] args) {
        Rex rex = new Rex();
        rex.studyJava();
        rex.studyJs();
        rex.studyPython();
    }

依赖注入

public class Rex {
    public void studyCourse(ICourse iCourse){
        iCourse.studyCourse();
    }
}
//依赖倒置
    public static void main(String[] args) {
        Rex rex = new Rex();
        rex.studyCourse(new JavaCourse());
        rex.studyCourse(new JsCourse());
        rex.studyCourse(new PythonCourse());
    }

di

构造器注入(单例)

public class Rex {
    private ICourse iCourse;
    public Rex(ICourse iCourse) {
        this.iCourse = iCourse;
    }
    public void studyImoocCourse(){
        iCourse.studyCourse();
    }
}
//v3 构造器注入
public static void main(String[] args) {
        Rex rex = new Rex(new JavaCourse());
        rex.studyImoocCourse();
}

setter注入

public class Rex {
    private ICourse iCourse;
    public void setiCourse(ICourse iCourse){
        this.iCourse = iCourse;
    }
    public void studyImoocCourse(){
        iCourse.studyCourse();
    }
}
//v4 setter injection
public static void main(String[] args) {
        Rex rex = new Rex();
        rex.setiCourse(new JavaCourse());
        rex.studyImoocCourse();

        rex.setiCourse(new PythonCourse());
        rex.studyImoocCourse();

        rex.setiCourse(new JsCourse());
        rex.studyImoocCourse();
}

单一职责原则(Single Responsibility )

  • 不存在多于一个导致类变更的原因
  • 一个类、接口、方法只负责一个职责
  • 降低复杂度,提高可读性、可维护性、降低风险

类的单一原则

不遵循单一职责原则的例子

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("大雁");
    }
}

类的单一原则修改

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("大雁");
    }
}

sr

接口的单一原则

isr

方法的单一原则

每个方法对单一属性进行修改或者实现单一功能

接口隔离原则(Interface Segregation)

  • 采用多个接口,而不依赖于单一总接口
  • 一个类与一个类的依赖应该建立在最小的接口上
  • 接口尽量小、尽量细化
public interface IAnimalAction {
    void eat();

    void fly();

    void swim();
}
public interface IFlyAnimalAction {
    void fly();
}
public interface ISwimAnimalAction {
    void swim();
}
public interface IEatAnimalAction {
    void eat();
}

需要适度

is

比起单一职责,更倾向于架构,接口,而不是功能

迪米特原则(最少知道)

  • 一个对象应该对其他对象保持最少的了解
  • 降低类与类的耦合
  • 只和朋友类保持关系(内部使用的类不是朋友类)

demeter

里氏替换原则(Liskov Substitution,LSP)

  • 如果软件可以适用父类,那一定能适用子类
  • 子类可以拓展父类的功能,但不能改变已有的功能
  • 子类可以实现父类的抽象方法,但不能修改非抽象方法
  • 子类可以增加方法
  • 重载方法时,入参应当更宽松
  • 子类重载或重写方法时,输出要更严格

  • 有效约束继承泛滥,体现开闭原则

  • 增加健壮性、拓展性

不符合里氏替换的例子

public class Rectangle {
    private long length;
    private long width;

    @Override
    public long getWidth() {
        return width;
    }

    @Override
    public long getLength() {
        return length;
    }

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

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

    public long getSideLength() {
        return sideLength;
    }

    public void setSideLength(long sideLength) {
        this.sideLength = sideLength;
    }

    @Override
    public long getWidth() {
        return sideLength;
    }

    @Override
    public long getLength() {
        return sideLength;
    }
}
public static void resize(Rectangle rectangle){
        while (rectangle.getWidth() <= rectangle.getLength()){
            rectangle.setWidth(rectangle.getWidth()+1);
            System.out.println("width:"+rectangle.getWidth() + " length:"+rectangle.getLength());
        }
        System.out.println("resize方法结束 width:"+rectangle.getWidth() + 
                           " length:"+rectangle.getLength());
    }

新建上层接口

lsp

从而避免了resize中传入square,因为square不再是rectangle子类

合成复用原则

  • has-A & contains-A 代替 is-A
  • 降低耦合
public abstract class DBConnection {
    //    public String getConnection(){
//        return "MySQL数据库连接";
//    }
    public abstract String getConnection();
}
public class MySQLConnection extends DBConnection {
    @Override
    public String getConnection() {
        return "MySQL数据库连接";
    }
}
public class PostgreSQLConnection extends DBConnection {
    @Override
    public String getConnection() {
        return "PostgreSQL数据库连接";
    }
}
public class ProductDao{
    private DBConnection dbConnection;

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

    public void addProduct(){
        String conn = dbConnection.getConnection();
        System.out.println("使用"+conn+"增加产品");
    }
}
public class Test {
    public static void main(String[] args) {
        ProductDao productDao = new ProductDao();
        productDao.setDbConnection(new PostgreSQLConnection());
        productDao.addProduct();
    }
}

ca

  • Copyrights © 2019-2020 Rex