Design Principles - Synthesis and Reuse Principles

Principle of composition and reuse: try to use composition/collection between classes, followed by inheritance

meaning

  • The principle of synthetic reuse ( Composite/Aggregate Reuse Principle, CARP) refers to using object combination (has-a) and aggregation (contanis-a ) as much as possible instead of inheritance relationships to achieve the purpose of software reuse. It can make the system more flexible and reduce the coupling between classes. Changes in one class will have relatively little impact on other classes.

  • Inheritance is called white-box reuse, which is equivalent to exposing all implementation details to subclasses. Combination/aggregation is also called black box reuse, and the implementation details cannot be obtained for objects other than classes.

main idea

  • Prioritize the use of aggregation and combination instead of inheritance

Method to realize

The principle of synthetic reuse is achieved by incorporating existing objects into new objects as member objects of the new object. The new object can call the functions of the existing objects, thereby achieving reuse.

Basic methods of reuse

Generally, class reuse can be divided into two types: inheritance reuse (using inheritance to achieve code reusability) and synthetic reuse (using combination or aggregation to achieve code reusability).

  1. Combination/aggregation (synthetic reuse)

    • The difference between aggregation and combination:

      • Aggregation is used to express ownership relationships or relationships between wholes and parts.
      • Combination represents a much stronger ownership relationship. In the combination, the life cycle of the part and the whole is the same . A new combined object has full control over its component parts, including their creation and destruction. Component objects in one composition relation cannot be shared with another composition relation. A component can only belong to one combination relationship at the same time
  2. Inheritance (inheritance reuse)

The difference between the two methods of reuse

  1. Combination/Aggregation: Incorporating existing objects into new objects to make them part of the new object

    • advantage

      1. The coupling between objects is low , and composition or aggregation itself is less coupled than inheritance. When we actually use composition or aggregation reuse, we can declare an abstract parent class or parent interface in the member position of the class, so that we can dynamically pass the subclass object of the abstract class or parent interface.
      2. The encapsulation of the class is maintained , because the internal details of the member object are invisible to the new object, which means that the new object does not know the specific implementation of the member object, but can call its functions, so this kind of reuse is also called Reuse for black box
      3. Reuse has high flexibility . This reuse can be performed dynamically at runtime. New objects can dynamically reference objects of the same type as component objects. That is to say, if we want to assign values ​​to member variables, then we can It is assigned a value only when it is run. If the member position declares an abstract class or interface, we can pass the interface or a subclass object of the class.
    • shortcoming

      1. Systems built through reuse in this way will have more objects to manage.
  2. Inheritance: It is a unique reuse tool for object-oriented, and it is also the most easily abused. Inheritance reuse extends the implementation of an existing object to obtain new functionality

    • advantage

      1. Simple and easy to implement, because most functions of the parent class can automatically enter the subclass through inheritance relationships, and it is also easier to modify or extend the inherited implementation.
    • shortcoming

      1. It destroys the encapsulation of the class , because inheritance will expose the implementation details of the parent class to the subclass, which means that the subclass can directly inherit the functions of the parent class, so that the subclass can override the functions of the parent class. Lost, so the parent class is transparent to the child class. In fact, this kind of reuse can also be called white box reuse.
      2. The coupling degree between the subclass and the parent class is high . Any changes in the implementation of the parent class will lead to changes in the implementation of the subclass. Modifying the parent class will cause a chain reaction, which is not conducive to the expansion and maintenance of the class.
      3. Limiting the flexibility of reuse , the implementation inherited from the parent class is static. This is because it has been defined at compile time, so it is impossible to change at runtime. We can't always say that while the program is running, let's cancel the inheritance relationship between the subclass and the parent class! Moreover, this is impossible to achieve, so we say that inheritance limits the flexibility of reuse.
    • Note: If inheritance is used, the Liskov substitution principle must be strictly followed . The synthesis reuse principle and the Liskov substitution principle complement each other, and both are specific implementation specifications of the opening and closing principle .

Case

Car classification

According to the power source, cars can be divided into electric cars, gasoline cars...; according to the color , they can be divided into black, white, red...; considering the above two methods at the same time, there are many cars that can be combined

If inheritance reuse is used, the designed UML class diagram is

Inheritance and reuse

Inheritance and reuse

As can be seen from the above class diagram, a top-level parent class is first defined, that is, the car class, and there are two subclasses under this class, one is the gasoline car class, and the other is the electric car class. There are three subcategories under the gasoline car category: gasoline cars in black, red, and white colors; the same goes for electric cars, and electric cars in black, red, and white colors.

Using inheritance and reuse creates many subclasses. If there is a new power source now, such as hydrogen cars, then we have to add a new subclass to the above class diagram, and we have to add more subclasses, because hydrogen cars also have to Divide by color.

Inheritance and reuse-new hydrogen energy vehicle class

Inheritance and reuse-new hydrogen energy vehicle class

code

public abstract class Car {
    
    
    public abstract void run();
}
// 汽油、氢能都类似
public class ElectricCar extends Car {
    
    
    @Override
    public void run() {
    
    
        System.out.println(" - 电动车");
        //System.out.println(" - 汽油车");
    }
}
// 红、黑、白色电动车类似
public class RedElectricCar extends ElectricCar {
    
    
    public void go() {
    
    
        System.out.print("红色");
        run();
    }
}
// 红、黑、白色汽油车类似
public class RedPetrolCar extends PetrolCar {
    
    
    public void go() {
    
    
        System.out.print("红色");
        run();
    }
}

Main

public static void main(String[] args) {
    
    
    BlackPetrolCar blackPetrolCar = new BlackPetrolCar();
    blackPetrolCar.go();
}

Insert image description here

Case improvements:

Inheritance reuse changed to composition reuse

Inheritance and reuse

Inheritance and reuse

Synthetic multiplexing

Synthetic multiplexing

First, let’s look at the right part of the above class diagram. In this part, we define a color interface, and the interface has three sub-implementation classes, one is Black class, White class, and Red class; in the left part of the above class diagram , we have defined a top-level parent class, that is, the car class, and this class is also combined into the Color interface. That is to say, when we create a car object, we need to pass it a specific color subclass object. . In addition, this car category has two subcategories, one is the gasoline car category and the other is the electric car category.

code

public interface Color {
    
    
    void colorKind();
}
public abstract class Car {
    
    
    public abstract void run();

    Color color;

    public Color getColor() {
    
    
        return color;
    }

    public void setColor(Color color) {
    
    
        this.color = color;
    }
}
public class ElectricCar extends Car {
    
    
    @Override
    public void run() {
    
    
        System.out.println(" - 电动车");
    }
}
public class White implements Color{
    
    
    @Override
    public void colorKind() {
    
    
        System.out.println("白色");
    }
}

Main

public static void main(String[] args) {
    
    
	ElectricCar electricCar = new ElectricCar();
    White white = new White();
    electricCar.setColor(white);
    electricCar.getColor().colorKind();//白色
    electricCar.run();//电动汽车
}

Insert image description here

If there is an additional power source, such as a hydrogen car, the UML class diagram would be as follows

Synthetic multiplexing

Synthetic multiplexing

Just add a new subcategory under the automobile category

Case 2

Suppose there are two classes A and B. Class B needs to reuse the methods of class A

The above case is implemented through the principle of synthetic reuse , and inheritance reuse is no longer shown.

method one

Use simple dependencies . Add a method in class B, and use class A to input parameters to the method

// 测试类
public class Test {
    
    
  public static void main(String[] args) {
    
    
    B b = new B();
    b.methodB(new A());
  }
}

// A类
class A {
    
    
  public void methodA() {
    
    
    System.out.println("A类的方法执行了。");
  }
}

// B类
class B {
    
    
  public void methodB(A a) {
    
    
    System.out.println("B类的方法执行了。");
    a.methodA();
  }
}

Method 2

Aggregate class A into class B. Add attributes in class B, the type is class A, and initialize it through the set method

// 测试类
public class Test2 {
    
    
  public static void main(String[] args) {
    
    
    B b = new B();
    System.out.println("使用聚合的执行结果:");
    b.setA(new A());
    b.methodB();
  }
}

// A类
class A {
    
    
  public void methodA() {
    
    
    System.out.println("A类的方法执行了。");
  }
}

// B类
class B {
    
    
  private A a;
  public A getA() {
    
    
    return a;
  }
  public void setA(A a) {
    
    
    this.a = a;
  }
  public void methodB() {
    
    
    System.out.println("B类的方法执行了。");
    this.a.methodA();
  }
}

Method three

Combine class A into class B. Add attributes in class B, the type is class A, and directly new it out

public class Test3 {
    
    
  public static void main(String[] args) {
    
    
    B b = new B();
    System.out.println("使用组合的执行结果:");
    b.methodB();
  }
}

class A {
    
    
  public void methodA() {
    
    
    System.out.println("A类的方法执行了。");
  }
}

class B {
    
    
  private A a = new A();
  public void methodB() {
    
    
    System.out.println("B类的方法执行了。");
    this.a.methodA();
  }
}

Guess you like

Origin blog.csdn.net/qq_42700109/article/details/132836907