Large Java Advanced topics (C) software architecture design principles (under)

Foreword

The second lesson we begin the topic of today, the next chapter to continue sharing software architecture design principles will be introduced: the interface segregation principle, the principle of Demeter, Richter substitution principle and synthetic multiplexing principles. This chapter reference books "Spring 5 core principles" in the first chapter Spring internal organs Heart (no electronic gear, combined with its essence is my own understanding, a word a word to knock them out of the hand).

Interface Segregation Principle

Interface segregation principle (Interface Segregation Principke, ISP) refers to the use of a plurality of dedicated interfaces, interfaces without using the single general, the client should not rely on it does not interface. We know that this principle should note the following when designing the interface:

(1) a class dependent on another class of the interface should be based on a minimum.

(2) establish a single interface, do not create bloated interface.

(3) Interface possible refinement process to minimize interface (not better, must be appropriate).

Interface segregation principle in line with what we often say high cohesion and low coupling design, the class can have a good readability, scalability and maintainability. We have to think about the design of the interface of the time, spend time, to consider the business model, including where possible changes in the future to do some pre-judgment. So, for the abstract, to understand the business model is very important.

Here we look at a piece of code, an animal behavior to abstract description.

//描述动物行为的接口
public interface IAnimal {
    void eat();
    void fly();
    void swim();
}
//鸟类
public class Bird implements IAnimal {
    public void eat() {
    }

    public void fly() {
    }

    public void swim() {
    }
}
//狗
public class Dog implements IAnimal {
    public void eat() {
    }

    public void fly() {
    }

    public void swim() {
    }
}

As can be seen, the Swim Brid () method can only be empty, and the Dog Fly () method is obviously impossible. At this time, we focused on different animal behavior to design different interfaces were designed IEatAnimal, IFlyAnimal and ISwimAnimal interfaces, look at the code:

public interface IEatAnimal {
    void eat();
}
public interface IFlyAnimal {
    void fly();
}
public interface ISwimAnimal {
    void swim();
}

At this point only need to implement IEatAnimal Dog and ISwimAnimal interface can be, so the clarity.

public class Dog implements IEatAnimal,ISwimAnimal {

    public void eat() {
    }

    public void swim() {
    }
}

Dmitry principle

Dimitris principle (Law of Demeter LoD) refers to an object to be kept to a minimum understanding of other objects, also known as the least known principle (Least Knowledge Principle, LKP), to minimize the degree of coupling between the class and class. Dimitris main emphasis principle: to communicate with friends only, do not talk to strangers. Appears in the member variable, process input and output parameters may be referred to as members of the class friend class, now inside out method body does not belong to the class friends category.

Now design a permissions system, Boss need to find out the number of courses to release the line. At this time, Boss TeamLeader to find statistics, TeamLeader statistical results and then tell Boss, let's look at the code:

//课程类
public class Course {
}
//TeamLeader类
public class TeamLeader {
    public void checkNumberOfCourses(List<Course> courses){
        System.out.println("目前已经发布的课程数量:"+courses.size());
    }
}
//Boss类
public class Boss {
    public void commandCheckNumber(TeamLeader teamLeader){
        //模拟BOSS一页一页往下翻页,TeamLeader实时统计
        List<Course> courseList = new ArrayList<Course>();
        for (int i = 0; i < 20; i++) {
            courseList.add(new Course());
        }
        teamLeader.checkNumberOfCourses(courseList);
    }
}
//调用方代码
public static void main(String[] args) {
        Boss boss = new Boss();
        TeamLeader teamLeader = new TeamLeader();
        boss.commandCheckNumber(teamLeader);
}

I write to you, in fact, function has been achieved, the code appears to be no problem, but according to the principles of Demeter, Boss just want results, do not want to communicate directly with the Course. TeamLeader statistics need to reference the Course object. Boss and Course are not friends and can be seen from the following class diagram:

The following code to transform:

//TeamLeader做与course的交流
public class TeamLeader {
    public void checkNumberOfCourses(){
        List<Course> courses = new ArrayList<Course>();
        for (int i = 0; i < 20; i++) {
            courses.add(new Course());
        }
        System.out.println("目前已经发布的课程数量:"+courses.size());
    }
}
//Boss直接与TeamLeader交流,不再直接与Course交流
public class Boss {
    public void commandCheckNumber(TeamLeader teamLeader){
        //模拟BOSS一页一页往下翻页,TeamLeader实时统计
        teamLeader.checkNumberOfCourses();
    }
}

Look at the class diagram, Boss has been no contact with the Course

Bear in mind here, learning software design rule, do not form obsessive-compulsive disorder, encounter complex business scenarios, we need to act according to circumstances.

Richter substitution principle

Richter substitution principle (Liskov Substitution Priciple, LSP) means that if for each type of objects O1 T1, T2 are the type of object O2 such that all program defined P T1 are replaced in all objects O1 O2 , the behavior of the program P has not changed, then the type is a subtype of type T2 T1.

This definition seems quite abstract, we have to re-understand it. Can be understood as a software entity, if applied to a parent class, then it must apply its subclasses, the reference places the parent class must be transparent to the use of the object which subclass, subclass object can be replaced with the parent object, and the program logic is not change, according to this understanding, extended meaning: subclass can extend the functionality of the parent class, but can not change the parent class of the original function.

(1) sub-class may implement the abstract parent class, but non-abstract parent class can not be covered.

(2) sub-class may increase their own unique methods.

Preconditions (3) when the parent class subclass overloaded, the method (i.e., input method, the reference) Method input parameters than the parent class is more relaxed.

(4) When the parent class implementation subclass (rewrite or reload implement the abstract methods), post-conditions of the process (i.e. the output of the method, the return value) or more stringent than the parent and the parent the same category.

Use Richter substitution principle has the following advantages:

(1) constraints inherited flooding, it is a reflection of the principle of opening and closing.

Robustness (2) to strengthen the program, when colleagues change can do a very good compatibility, improve the maintainability and scalability of the program, reduce the risk of introduction when demand becomes.

Now to describe a classic business scenario, relations with square, rectangular and quadrangular explanation Richter substitution principle, we all know that a square is a special rectangle, so you can create a parent class Rectangle:

//矩形类
public class Rectangle {
    private long hight;
    private long width;

    public long getHight() {
        return hight;
    }

    public void setHight(long hight) {
        this.hight = hight;
    }

    public long getWidth() {
        return width;
    }

    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 getHight() {
        return super.getHight();
    }

    @Override
    public void setHight(long hight) {
        super.setHight(hight);
    }

    @Override
    public long getWidth() {
        return super.getWidth();
    }

    @Override
    public void setWidth(long width) {
        super.setWidth(width);
    }
}
public class DemoTest {
    //在测试类中创建resize方法,长方形的宽应该大于等于高,我们让高一直增加,直至高等于宽,变成正方形。
    public static void resize(Rectangle rectangle) {
        while (rectangle.getWidth() >= rectangle.getHight()){
            rectangle.setHight(rectangle.getHight()+1);
            System.out.println("宽度:"+rectangle.getWidth()+"高度:"+rectangle.getHight());
        }
        System.out.println("resize方法结束!");
    }

    //测试代码如下
    public static void main(String[] args) {
        Rectangle rectangle = new Rectangle();
        rectangle.setHight(10);
        rectangle.setWidth(20);
        resize(rectangle);
    }

Look at the console output, and finally found the height greater than the width, this situation is normal in the case of a square, now we replace the Rectangle class into a subclass, it would not be logical, and contrary to the principle of replacing Richter, after replacing the parent class into subclasses result of the program did not meet expectations. Therefore, there are certain risks of our code design. Richter substitution principle exists only between parent and child classes, inheritance constraints flooding. Let us create a common abstract interface based on square and rectangular quadrilateral Interface Quadrangle:

public interface Quadrangle { 
    long getWidth(); 
    long getHeight(); 
}

Modify class Rectangle rectangle:

public class Rectangle implements Quadrangle {
    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;
    }
}

Modify square class Square categories:

public class Square implements Quadrangle {
    private long length;

    public long getLength() {
        return length;
    }

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

    public long getWidth() {
        return 0;
    }

    public long getHeight() {
        return 0;
    }
}

At this time, if we put a resize parameter () method of the class into a quadrangle Quadrangle, internal method will be given. Because the square Square has no setWidth () and setHeight () method has. Accordingly, in order to restrict the proliferation of inheritance, a resize () method parameters can only Rectangle rectangle. Of course, we will continue to thoroughly explain later in the design mode courses.

Synthesis of multiplexing principles

Synthesis of multiplexing principles (Composite / Aggregate Reuse Principle, CARP) refers to the possible object composition (has-a) / polymerized (contanis-a), instead of inheritance purposes of software reuse. You can make the system more flexible, to reduce the coupling between the class and class, a relatively small change in the influence of other classes class caused. Our inheritance is called white-box reuse, which is equivalent to all of the implementation details are exposed to the subclass. Composition / polymerization also known as black box multiplexed objects can not be accessed outside the class implementation details. To do code design based on specific business scenarios, in fact, need to follow OOP model. Or in database operations, for example, to create the first DBConnection categories:

public class DBConnection { 
    public String getConnection(){ 
        return "MySQL 数据库连接"; 
    } 
}

Creating ProductDao categories:

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+"增加产品"); 
    } 
}

This is a very typical synthesis multiplexing principle scenarios. However, the current designs, DBConnection is not an abstraction, not easy system expansion. The current system supports the MySQL database connection, assuming that business changes, database operations to support Oracle database layer. Of course, we can add support for Oracle database method in DBConnection in. But contrary to the principle of opening and closing. In fact, we do not have to modify the code Dao, DBConnection will modify the abstract, look at the code:

public abstract class DBConnection { 
    public abstract String getConnection(); 
}

Then, the logic pulled MySQL:

public class MySQLConnection extends DBConnection { 
    @Override 
    public String getConnection() { 
        return "MySQL 数据库连接"; 
    } 
}

Oracle re-create the logical support of:

public class OracleConnection extends DBConnection { 
    @Override 
    public String getConnection() { 
        return "Oracle 数据库连接"; 
    } 
}

The particular choice to the application layer, look class diagram:

Summary of Design Principles

Learning design principles, learning the basic design patterns. In the actual development process, not necessarily require that all the code follows the design principle, we have to consider manpower, time, cost, quality, not deliberately pursuit of perfection, to follow the design principles in appropriate scene, embodies a kind of trade-offs, help us design a more elegant code structure.

Guess you like

Origin www.cnblogs.com/whgk/p/12465380.html