Dependency inversion principle

  • define
    • 1. Upper modules should not depend on lower modules, they should all depend on abstractions
    • 2. Abstraction should not depend on details. Details should depend on abstractions
    • 3. High-level modules cannot depend on low-level modules; both should depend on abstractions
    • 4. The business layer is in the upper module, while the logical layer and data layer are in the bottom
  • advantages
    • Through abstraction to build the framework, the establishment of class and class association, in order to reduce the coupling between classes. Moreover, the system built by abstraction is more stable, more expansible and easier to maintain than the system built by concrete implementation.
  • Explain with code examples
    • A pizza shop can produce all kinds of pizza
    • Sorting out the bottom and the top, the pizzeria is naturally the top, pizza is the bottom. Start from the inertia of logical thinking
    • PizzaStore relies on all Pizza objects because he can create Pizza objects
    • There are many kinds of pizzas
      • Like cheese pizza
      • Vegetarian pizza
      • Seafood pizza
      • , etc.

Bad design

  • Instead of relying on the abstract, the concrete depends on the concrete, and the pizza shop depends on the concrete pizza class
  • Create a pizza class that loves you
typedef enum : NSUInteger {
    PizzaTypeOne,
    PizzaTypeTwo,
    PizzaTypeThree,
} PizzaType;
@interface PizzaStore : NSObject
- (NSObject *)creatPizzaWithType:(PizzaType)type;

Copy the code
  • Depending on the enumerated values, their specific creation methods are called separately
@implementation PizzaStore
- (NSObject *)creatPizzaWithType:(PizzaType)type{
    if (type == PizzaTypeOne) {
        return [PizzaOne makePizzaOne];
    }
    if (type == PizzaTypeTwo) {
        return [PizzaTwo makePizzaTwo];
    }
    if (type == PizzaTypeThree) {
        return [PizzaThree makePizzaThree];
    }
    return nil;
}
@end
Copy the code
  • The downside is that as the demand gets bigger and bigger and the variety of pizzas gets bigger and bigger and they have different constructors that are unique to them, you need to call them in the store class too, be careful not to call them wrong.

  • Dependency inversion:

    • Let’s start at the bottom and think about, can a lot of pizza types, a lot of different ways to create a pizza be able to use the same method and then rewrite your own method in a subclass. So we came up with a pizza class. An abstract class, then an abstract method of construction, and then the design shop
    #import "PizzaNew.h"
    NS_ASSUME_NONNULL_BEGIN
    typedef enum : NSUInteger {
        PizzaTypeNewOne,
        PizzaTypeNewTwo,
        PizzaTypeNewThree,
    } PizzaNewType;
    
    @interface PizzaNewStore : NSObject
    - (PizzaNew *)creatPizzaWithNewType:(PizzaNewType)type;
    
    Copy the code
    - (PizzaNew *)creatPizzaWithNewType:(PizzaNewType)type{
    if (type == PizzaTypeNewOne) {
        return [PizzaNewOne makePizza];
    }
    if (type == PizzaTypeNewTwo) {
        return [PizzaNewTwo makePizza];
    }
    if (type == PizzaTypeNewThree) {
        return [PizzaNewThree makePizza];
    }
    return nil;
    }
    Copy the code
    • It doesn’t make much of a difference. The same enumeration creates different subclasses.

    • One thing to note is that the new build method has an abstract class, which helps us make our code more flexible and extensible

    • 1. Add attributes We can add in the abstract class, subclass attributes inherit parent class.

      • @property(nonatomic,assign)BOOL KK; // It is used to judge whether pizza is new or not. The default is set to NO in the constructor.

      • When we create a new pizza subclass we can re-construct the method and set the new subclass KK property to Yes to indicate that the pizza is new. Instead of adding its own attributes to each pizza class

      • You can also use this abstract class to write all of pizza’s basic attributes

      • If a subclass has its own attributes, you can add them to the subclass. This complies with the open/close principle

  • How to practice

In the future, when dealing with the interaction of high and low level modules (classes), we should try our best to remove the dependence of the two by abstract means, which can be implemented through interfaces or abstract classes.