After two months, I finally finished the beauty of Design Patterns by Wang Zheng, with 73 articles.

This book is still worth reading, the author of the design concept, design mode of deep thinking, and the use of these ideas to the actual work, so that the design mode is not so empty; In addition, this book spends a lot of space to talk about the design concept, which is relatively transparent, which is rare, because no matter what kind of design mode, will eventually reflect back to the concept, design concept is the fundamental thing.

By reading books on design patterns, I have now completed 5 articles:

  1. Go Design Pattern (5)- Class diagram symbolic representation
  2. Go Design Pattern (4)- Code writing optimization
  3. Go Design Pattern (4)- Code writing
  4. Go Design Patterns (3)- Design principles
  5. Go Design Pattern (2)- Object-oriented analysis and design
  6. Go Design Pattern (1)- Syntax

Later, I will also enter the writing of the design mode article. Although this leads to a slow learning progress, it is worthwhile to grasp these knowledge more firmly.

Here are the reading notes, you can have a look, if you feel suitable, you can go to geek time to buy the full book.

Reading notes

  1. The opening words

    • We write code that works, and we never grow up to be the best
    • Written code saves time in the future
  2. Why should every programmer learn and master design patterns early

    • Answer questions about design patterns in the interview;
    • Say goodbye to writing bad code that people make fun of;
    • Improve the design and development ability of complex code;
    • Let read the source code, learning framework multiplier;
    • Prepare for your career development
  3. What are the dimensions of code quality? How do I have the ability to write high-quality code?

    • Maintainability: “Code maintainable” is the ability to change or add code quickly without breaking the original code design or introducing new bugs.
    • Readability: It depends on whether the code conforms to the code specification, whether the name is reasonable, whether the comments are detailed, whether the function length is appropriate, whether the modules are clearly divided, whether the code conforms to high cohesion and low coupling, etc
    • Extensibility: Extensibility of code means that we add new functional code by extension without modifying or modifying the original code in small amounts.
    • Flexibility: Code is flexible if it is easy to extend, reuse, or use. So, the word flexible has a very broad meaning and can be used in many situations
    • Simplicity: Code is simple and logical, which means easy to read and maintain
    • Reusability: minimize the writing of duplicate code and reuse existing code
    • Testability: Poor testability of code makes it difficult to write unit tests, which is basically a sign that the code is not designed properly
  4. What is the relationship between object orientation, design principles, design patterns, programming specifications, and refactoring?

  5. Theory 1: What are we really talking about when we talk about object orientation?

    • Object-oriented programming is a programming paradigm or style. It takes class or object as the basic unit of code organization, and takes encapsulation, abstraction, inheritance and polymorphism as the cornerstone of code design and implementation.
    • Object-oriented programming language is a programming language that supports the syntax mechanism of class or object, and has a ready-made syntax mechanism, which can easily realize the four features of object-oriented programming (encapsulation, abstraction, inheritance, polymorphism).
  6. Theory 2: What programming problems can encapsulation, abstraction, inheritance, and polymorphism solve?

    • Encapsulation: also called information hiding or data access protection. By exposing a limited access interface, a class authorizes outsiders to access internal information or data only through the means (or functions) provided by the class.
    • Abstract: Human’s effective means of dealing with complexity
    • Inheritance: One of the biggest benefits of inheritance is the reuse of code to represent IS-A relationships between classes
    • Polymorphism: Improves code extensibility and reuse
  7. Theory 3: What are the advantages of object orientation over process orientation? Is process orientation really obsolete?

    • Object-oriented programming is more able to deal with this complex type of program development than procedural programming. Compared with procedural programming, object-oriented programming has more features (encapsulation, abstraction, inheritance, polymorphism). The code written by using these features is easier to expand, reuse and maintain.
  8. Theory 4: What code design looks like object oriented but is actually process oriented?

    Process-oriented programming style is in line with people’s process-oriented thinking mode; Object-oriented programming, on the other hand, is a bottom-up way of thinking.

    • Abusing getters and setters
    • Constants, Utils class design problems
    • Development model based on anemia model
  9. Theory 5: Interface vs. Abstract Class difference? How do ordinary classes emulate abstract classes and interfaces?

    • An abstract class is really just a class, just a special kind of class that cannot be instantiated as an object and can only be inherited by subclasses. We know that the inheritance relation is an IS-A relation, and the abstract class, since it belongs to a class, also represents an IS-A relation. In contrast to the IS-A relationship of an abstract class, an interface represents a HAS-A relationship that has some functionality. Interfaces are more figuratively known as contracts.
    • Abstract classes are more for code reuse, and they can elegantly guarantee polymorphism
    • Interfaces focus more on decoupling
    • If we want to represent an IS-A relationship, and to solve the problem of code reuse, we use abstract classes. If we want to represent a HAS-A relationship, and to solve the problem of abstraction rather than code reuse, we can use interfaces.
  10. Theory 6: Why program based on interfaces rather than implementation? Is it necessary to define interfaces for each class?

    • Another way to express the principle of programming based on interfaces, not implementations, is “programming based on abstractions, not implementations.”
    • The more abstract, top-level, and implementation-free your design is, the more flexible your code will be and the more responsive it will be to future requirements. Good code design not only responds to the needs of the present, but is flexible enough to respond to future requirements without breaking the original code design.
  11. Theory 7: Why more composition and less inheritance? How do you decide whether to use composition or inheritance?

    • Inheritance has many functions, but inheritance level is too deep, too complex, will affect the maintainability of code

    • Inheritance has three main functions: representing IS-A relationships, supporting polymorphic characteristics, and code reuse. These three functions can be achieved by combination, interface and delegation. In addition, using composition can also solve the problem of code maintainability caused by too deep and complex inheritance relationship.

  12. Practice 1: Does the anaemic model-based MVC architecture commonly used in business development violate OOP?

    • Classes that contain only data and no business logic are called anemic models
    • The data and the corresponding business logic are encapsulated in the same class, called the congestion model
    • The traditional development mode based on anaemia model emphasizes Service but not BO; DDD development mode based on congestion model, light Service heavy Domain
  13. Actual Combat 1 (ii): How to develop a virtual wallet system using DDD based on congestion model?

    • For a transfer like payment, we record the transaction flow and mark it as “pending” before moving the balance between the two wallet accounts. When both wallets have been added or subtracted, we go back and mark the transaction flow as “successful.” If either operation fails in the process of adding or subtracting money from both wallets, we mark the status of the transaction record as “failed.” Through the background Job, we pull the transaction records that are in the “failed” state or in the “pending” state for a long time and re-execute them or process them manually.
  14. Actual combat 2 (PART 1): how to do object-oriented analysis on interface authentication?

    • Object – oriented analysis (OOA), object – oriented design (OOD) and object – oriented programming (OOP) are the three main links of object – oriented development
  15. Practice 2: How to use object-oriented design and programming interface authentication function?

    • The output of object-oriented analysis is a detailed description of requirements
    • The outputs of object-oriented design are classes
      • Divide responsibilities to identify categories: list nouns or function points
      • Define classes and their attributes and methods: We identify the verbs in the requirements description as candidate methods, further filter out the real methods, and use the nouns involved in the function points as candidate attributes, and then filter and filter again.
      • Define the interaction relationships between classes: generalization, implementation, association, aggregation, composition, and dependency. Only four relationships remain: generalization, implementation, composition, and dependency
      • Assemble classes and provide entry to execution
  16. Theory 1: For the single responsibility principle, how do you determine if a class’s responsibilities are single enough?

    • Single responsibility principle: a class is responsible for only one responsibility or function. Don’t design large, comprehensive classes. Design small, single-purpose classes. The principle of single responsibility is to achieve high cohesion and low coupling of code, and improve code reusability, readability, and maintainability
    • In fact, in real software development, we don’t need to be too proactive and over-design. So, we can start by writing a coarse-grained class that meets our business needs. As the business grows, if the coarse-grained class gets bigger and bigger, and the code gets more and more, then we can split the coarse-grained class into several more fine-grained classes. This is called continuous refactoring. Some common judgment indicators:
      • Too many lines of code, functions, or attributes in a class;
      • A class depends on too many other classes, or depends on too many other classes;
      • Too many private methods;
      • It can be difficult to name a class properly;
      • A large number of methods in a class operate on a few properties of the class.
  17. Theory 2: How to open for expansion and close for modification? What do extensions and modifications mean?

    • Open closed principle: Add a new function by extending the existing code (adding modules, classes, methods, attributes, etc.) rather than modifying the existing code (modifying modules, classes, methods, attributes, etc.). There are two things to note about this definition. The first point is that the open closed principle does not mean that changes are completely eliminated, but that new features can be developed with minimal changes to the code. Second, the same code change may be considered a “change” under coarse-code granularity. At a fine code granularity, it might be considered “extended.”
    • The most common ways to improve code extensibility are polymorphism, dependency injection, programming based on interfaces rather than implementations, and most design patterns
  18. Theory 3: How is LSP different from polymorphism? Which codes violate LSP?

    • Richter’s substitution principle: A subclass object can replace the parent object anywhere in the program, and ensure that the logical behavior of the original program remains unchanged and its correctness is not damaged.
    • The difference between polymorphism and Richter’s substitution principle: Polymorphism is a feature of object-oriented programming and a syntax of object-oriented programming languages. It’s an idea of code implementation. The interior substitution is a design principle, which is used to guide how to design the subclass in the inheritance relationship. The design of the subclass should ensure that when replacing the parent class, the logic of the original program is not changed and the correctness of the original program is not damaged.
  19. Theory 4: What are the three applications of the interface isolation principle? How should interfaces in principles be understood?

    • Interface isolation principle: a client should not be forced to rely on interfaces it does not need
    • The difference between the interface isolation principle and the single responsibility principle: The single responsibility principle applies to the design of modules, classes, and interfaces. The interface isolation principle provides a criterion for determining whether an interface has a single responsibility: indirectly by how callers use the interface.
  20. Theory 5: Inversion of control, inversion of dependency, dependency injection, what are the differences and relationships among these three?

    • Inversion of Control (IOC) : The framework provides an extensible code skeleton for assembling objects and managing the entire execution process. When programmers use the framework to develop, they only need to add the code related to their business to the reserved extension points, and then they can use the framework to drive the execution of the whole program flow. “Control” refers to the control over the flow of program execution, while “inversion” refers to the control of the entire program execution by the programmer himself before using the framework. After using the framework, the execution flow of the whole program can be controlled by the framework. Control of the process is “flipped” from the programmer to the framework.
    • Dependency injection (DI) : Instead of creating dependent class objects inside the class using new(), the dependent class objects are created outside the class and passed (or injected) to the class through constructors, function parameters, etc.
      • By passing in dependent class objects through dependency injection, code extensibility is improved and dependent classes can be replaced flexibly
    • Dependency Inversion principle (DIP) : High-level modules do not depend on low-level modules. High-level and low-level modules should depend on each other through abstractions. In addition, abstractions should not rely on details. Details should rely on abstractions.
  21. Theory 6: Why do I say the KISS and YAGNI principles seem so simple, but they are often used incorrectly?

    • The KISS rule: Keep it simple
      • Don’t implement code using techniques your colleagues may not understand
      • Don’t reinvent the wheel. Be good at using existing toollibraries
      • Don’t over-optimize
    • YAGNI Principle: You won’t need it
      • Design features that are not currently needed
      • Don’t write code that isn’t currently needed
      • Don’t overdesign
  22. Theory 7: Does repetitive code always violate DRY? How can you improve your code’s reusability?

    • The DRY rule: Don’t Repeat-Yourself, Don’t write duplicate code

    • There are three typical cases of code duplication: implementation logic duplication, functional semantic duplication, and code execution duplication

      • The implementation logic of the code is the same, but the semantics are different, and we determined that it does not violate the DRY principle

      • The code is implemented logically, but semantically, that is, functionally, repetitively, which we consider a violation of the DRY principle

      • There is “duplication of execution” in the code, which violates the DRY principle

    • Ways to improve code reusability

      • Reduce code coupling
      • Meet the single responsibility principle
      • modular
      • Separation of business and non-business logic
      • Common code sink
      • Inheritance, polymorphism, abstraction, encapsulation
      • Apply design patterns such as templates
    • RuleofThree: When we first wrote code, we didn’t think about reusability; The second time you encounter a reuse scenario, you refactor it to reuse it

  23. Theory 8: How to use Demeter’s Law (LOD) to achieve high cohesion, loose coupling?

    • High cohesion and low coupling
      • High cohesion: Similar functions should be placed in the same class, and unrelated functions should not be placed in the same class
      • Loose coupling: In code, the dependencies between classes are simple and clear
    • Demeter’s law: No dependencies between classes that should not have direct dependencies; Try to rely on only the necessary interfaces between classes that have dependencies
  24. Practice 1: How to do requirement analysis and design for business system development?

    • Object-oriented design is focused on the code level (mainly for classes), while system design is focused on the architecture level (mainly for modules), and there are many similarities between the two.
  25. Actual Combat 1 (ii): How to implement a points exchange system in accordance with the design principles?

    • What operations business development involves: interface design, database design, and business model design (also known as business logic)
    • Why MVC three-tier development
      • Layering helps code reuse
      • Layering can insulate change
      • Layering serves to isolate concerns
      • Layering improves the testability of your code
      • Layering deals with the complexity of the system
  26. Practice 2: How to do requirements analysis and design for non-business general framework development?

    • Software design and development is an iterative process, and the division between analysis, design and implementation is not obvious
    • Framework non-functional requirements: ease of use, performance, scalability, fault tolerance, versatility, etc
    • Complex framework design skills: drawing block diagrams of product lines, focusing on simple application scenarios, designing and realizing minimum prototypes, drawing system design drawings, etc
    • If we wait until everything is thought out before we start anything, it may never get started. There is an old saying that all things are difficult before they are easy, so it is important to take the first step
  27. Practice 2: How to implement a performance counter that supports various statistical rules?

    • Object-oriented design and implementation is all about putting the right code in the right classes
    • The criteria to choose which division method is to make the code as far as possible to meet the low coupling, high cohesion, single responsibility, open to expansion and closed to modify the various design principles and ideas mentioned before, as far as possible to make the code reusable, easy to read, easy to expand, easy to maintain
  28. Theory 1: When should YOU refactor? What exactly is refactoring? How do you refactor?

    • Definition: Refactoring is an improvement to the internal structure of software to make it easier to understand and less costly to modify without changing its visible behavior.
    • Junior engineers maintain code, senior engineers design code, and senior engineers refactor code
    • Reconfiguration can be roughly divided into large-scale high-level reconfiguration and small-scale low-level reconfiguration
  29. Theory 2: What are some of the best techniques for making refactoring error-free?

    • The most implementable and effective means of ensuring that refactoring does not go wrong is unit testing
    • Why write unit tests
      • Unit testing is a great way to find bugs in your code
      • Writing unit tests can help you find code design problems
      • Unit testing is a great complement to integration testing
      • The process of writing unit tests is itself a process of code refactoring
      • Reading unit tests can help you get familiar with the code quickly
      • Unit tests are implementable improvements to TDD
  30. Theory 3: What is testability in code? How to write testable code?

    • Reverse optimize code design by writing test cases. The code that is not testable is not designed well enough, and many of the design principles and ideas we talked about earlier, such as “programming based on interfaces, not implementation” and dependency inversion, are not followed. The refactored code is not only more testable, but also complies with classic design principles and ideas from a code design perspective.
    • The external services are detached through mock and secondary encapsulation.
    • Code testability: Code testability is how easy it is to write unit tests against your code. If a piece of code is difficult to unit test, or if unit tests are laborious to write and rely on advanced features in the unit testing framework, it often means that the code is not well designed or testable.
    • The most effective way to write testable code: Dependency injection is the most effective way to write testable code. Dependency injection allows us to mock out external services when writing unit tests, which is one of the most technically challenging aspects of writing unit tests.
    • Common anti-patterns: code with pending behavior logic, abuse of mutable global variables, abuse of static methods, use of complex inheritance relationships, highly coupled code
    • It really takes too long
  31. Theory 4: How to decouple code through encapsulation, abstraction, modularization, mid-tier, etc.?

    • Decoupling ensures loose coupling and high cohesion of code and is an effective method to control code complexity.
    • Measurement criteria: draw the dependencies between modules and classes, and judge whether decoupling reconstruction is needed according to the complexity of the dependency diagram.
    • Decoupling methods: encapsulation and abstraction, intermediate layer, modularization, design ideas and principles
  32. Theory 5: the 20 Coding Practices that Will Allow you to Improve Code Quality the Fastest (Part 1)

    • Naming: the key to naming is to be accurate, readable and thinking
    • Comments: The purpose of comments is to make code easier to read. There are three main aspects: what to do, why, and how to do it
  33. Theory 5: The 20 Coding Conventions that Will Allow you to Improve Code Quality the Fastest

    • Function/class size: no more than one screen
    • How long is appropriate for a line of code: no more than the width of the IDE display
    • Use blank lines to split cell blocks
  34. Theory 5: the 20 Coding Practices that Will Allow you to Improve Code Quality the Fastest

    • Distill complex logic into functions and classes
    • Excessive arguments can be handled by splitting them into functions or encapsulating them as objects
    • Do not use arguments in functions to control code execution logic
    • Function design should have a single responsibility
    • Remove excessive levels of nesting by removing redundant if or else statements, exiting nesting early using the continue, break, and return keywords, adjusting the execution order to reduce nesting, and abstracting some of the nested logic into functions.
    • Replace magic numbers with literal constants.
    • Use explanatory variables to explain complex expressions to improve code readability.
  35. Learn how to find code quality problems with an ID generator code

  36. Refactoring the ID generator code from usable to usable

    • Optimize according to the Checklist
    • Round 1 refactoring: Improve the readability of the code
    • Second refactoring: Improve the testability of your code
    • Third round of refactoring: Write good unit tests
    • Fourth refactoring: Add comments after all refactoring is complete
  37. Practice 2: What should I return if a program fails? NULL, exceptions, error codes, empty objects?

    • Function error returns data type, there are four cases, they are error code, NULL value, empty object, exception object
  38. Refactoring the exception handling code for each function in the ID generator project

    • As a programmer, at least the pursuit of code ah, or with salt fish what difference!
  39. Summarize and review object-oriented, design principles, programming specifications, reconstruction skills and other knowledge points

    • Good summary, highly recommended
  40. Apply the design principles and ideas learned to the performance counter project (PART 1)

    • Good design must be clear structure, logical, strong, look at a glance, after reading often have a feeling of the original. A bad design is often a mess of logic, code, no design ideas to speak of, seemingly baffling, and after reading it, confused
  41. Apply the design principles and ideas learned to the performance counter project (part 2)

    • Learn this step-by-step optimization method, as well as some of the programming skills involved, design ideas, can be used in other projects
  42. Singleton (part 1): Why is lazy double checking not better than hungry?

    • Singleton designpatterns are simple to understand. A class that allows only one object (or instance) to be created is a singleton class. This design pattern is called the singleton design pattern, or singleton for short.

    • Singleton usage: From the business concept, some data should only be saved in one copy of the system, which is better designed as a singleton class. For example, the system configuration information class. In addition, we can use singletons to resolve the problem of conflicting resource access.

    • Implement singleton pattern concerns:

      • Constructors need to be private to prevent external instances from being created through new;
      • Consider thread-safe object creation;
      • Consider whether lazy loading is supported;
      • Consider whether getInstance() is high performance (locked or not).
    • Singleton implementation:

      • Hungry type way is: at the time of class loading, the instance has to create and initialize the static instance, therefore, the instance instance creation process is thread-safe

      • Slacker has an advantage over hungrier in that it supports lazy loading. This approach requires attention to thread safety.

      • Double checking

      • Static inner class

      • The enumeration

  43. Singleton pattern (middle) : Why do I not recommend using singleton pattern? What are the alternatives?

    • Singletons are unfriendly to OOP feature support
    • Singletons hide dependencies between classes
    • Singletons are not extensibility friendly to code
    • Singletons are not testability friendly to code
    • Singletons do not support constructors that hold arguments
    • Alternatives include static methods, factory patterns, IOC containers, programmer guarantees, and so on
  44. Singleton pattern (2) : how to design and implement a distributed singleton pattern in a cluster environment?

    • A class that allows the creation of only one object (or instance) is a singleton class. This design pattern is called the singleton design pattern, or singleton for short. The only scope is in-process.
    • Threads are typically implemented using a HashMap
    • A cluster is equivalent to a collection of multiple processes. “Unique cluster” means unique within and between processes. That is, different processes share the same object and cannot create multiple objects of the same class. Singleton objects can be serialized and stored in external shared storage, locked when acquired, and released when used.
    • “Multi-example” means that a class can create multiple objects, but there is a limit to the number of objects, such as three. When a singleton class uses HashMap to store multiple objects, getInstance selects which object to use by passing the value.
  45. Factory Mode (part 1) : Why do I say don’t use factory mode to create objects?

    • When the creation logic of each object is simple, I recommend the simple factory pattern, where the creation logic of multiple objects is placed in a single factory class
    • When the creation logic is complex and a “big project”, we consider using the factory pattern to encapsulate the creation process of objects and separate the creation and use of objects
  46. Factory Pattern (2) : How to design and implement a Dependency Injection framework?

    • The DI container is a large factory class that is responsible for creating objects in advance at program startup based on the configuration of which class objects to create and which other class objects to rely on for each class object creation. When an application needs to use a class object, it simply gets it from the container. It is because it holds a bunch of objects that the framework is called a “container.”
    • The DI container has three core functions: configuration resolution, object creation, and object lifecycle management
    • The core logic of the DI container includes configuration file parsing and the creation of objects based on the configuration file through “reflection” syntax
  47. Constructor mode: details constructor, set method, builder mode three object creation methods

    • The factory pattern is used to create objects of different but related types (a group of subclasses that inherit from the same parent class or interface), with the parameters given to determine which type of object to create. Builder mode is used to create complex objects of one type, “customizing” different objects by setting different optional parameters.
    • Why the constructor pattern is used to create objects
      • We place the mandatory property of the class in the constructor, which is set when the object is created. With the set() method, there is no logic to verify that the required properties have been filled in
      • There are dependencies or constraints between the attributes of a class
      • You want to create immutable objects
  48. Prototype mode: How to clone a HashMap hash table the fastest?

    • If the cost of creating an object is high, and there is little difference between objects of the same class (most fields are the same), we can use the existing object (prototype) to copy (or copy) to create a new object, to achieve the purpose of saving creation time. This way of creating objects based on prototypes is called prototype design pattern, or prototype pattern for short.
    • There are two implementations of the prototype pattern, deep copy and shallow copy.
  49. Proxy mode: Proxy is used in RPC, cache, and monitoring scenarios

    • The Proxy Design Pattern adds functionality to the original class by introducing a Proxy class without changing the code of the original class (or proxy-class). You can have the proxy class implement the same interface as the original class or use inheritance.
    • The so-called Dynamic Proxy means that we do not write a Proxy class for each original class in advance, but dynamically create the corresponding Proxy class of the original class when running, and then replace the original class with the Proxy class in the system.
    • The proxy pattern is often used to develop non-functional requirements in business systems, such as monitoring, statistics, authentication, limiting, transactions, idempotent, and logging. We decoupled these additional functions from the business functions and placed them in a proxy class that allowed programmers to focus only on the business side of development. In addition, proxy mode can also be used in RPC, caching, and other application scenarios.
  50. Bridge mode: How to implement a message push system that supports different types and channels?

    • The bridge mode is limited in application scenarios and is not commonly used in real projects
    • The bridge pattern is defined as follows: “Decouple abstractions and implementations so that they can vary independently.
  51. Decorator pattern: Learn the decorator pattern by dissecting java-IO library source code

    • Decorator pattern mainly solves the problem that inheritance relationship is too complicated, and replaces inheritance by composition. Its main function is to add enhancements to the original class.
    • The first is that the decorator class inherits the same parent class as the original class, so we can “nest” multiple decorator classes to the original class.
    • The second is that decorator classes are enhancements to functionality, which is an important feature of the decorator pattern application scenario.
    • In the proxy mode, the proxy class adds functionality unrelated to the original class, while in the decorator mode, the decorator class adds enhancements related to the original class.
  52. Adapter patterns: Proxy, adapter, bridge, decorator, what is the difference between these four patterns?

    • There are two implementations: class adapters, which are implemented using inheritance relationships, and object adapters, which are implemented using composition relationships
    • How do you choose which one to use in real development? There are two criteria for judging: one is the number of Adaptee interfaces and the other is the degree of compatibility between Adaptee and ITarget.
    • Usage scenarios
      • Encapsulate a flawed interface design
      • Unify the interface design of multiple classes
      • Replace dependent external systems
      • Compatible with older interfaces
      • Adapt to different formats of data
    • Proxy pattern: The proxy pattern defines a proxy class for the primitive class without changing the interface of the primitive class. The primary purpose of the proxy pattern is to control access rather than enhance functionality, which is the biggest difference from the decorator pattern.
    • ** Bridge pattern: The purpose of the ** bridge pattern is to separate the interface part from the implementation part so that they can be changed relatively easily and independently.
    • Decorator pattern: The decorator pattern enhances the functionality of the original class without changing the interface of the original class and supports nested use of multiple decorators.
    • ** Adapter pattern: The ** adapter pattern is an afterthought strategy. The adapter provides a different interface from the original class, whereas the proxy and decorator patterns provide the same interface as the original class.
  53. Facade mode: How to design interface granularity to balance ease of use and universality?

    • Facade mode, also known as facade mode, provides a unified set of interfaces for subsystems, defining a set of high-level interfaces to make subsystems easier to use.
    • The quality of interface design directly affects whether the class, module, system is easy to use. So, we need to pay more attention to the interface design. I often say that interface design is half the task of development. As long as the interface is well designed, the code is not too bad.
    • Facade mode addresses ease of use, performance issues, and distributed transaction issues
  54. Composite pattern: How to design and implement a file system directory tree structure that supports recursive traversal?

    • In special application scenarios, data must be represented in a tree structure
    • Composition pattern: Organize a group of objects into a tree structure to represent a partial-whole hierarchy. Composition allows clients to unify the processing logic of individual objects and composite objects.
    • Organize a group of objects (files and directories) into a tree structure to represent a partial-whole hierarchy (nested structure of directories and subdirectories). Composite mode allows clients to unify the processing logic (recursive traversal) of a single object (file) and a composite object (directory).
  55. Share mode (1) : How to use share mode to optimize the memory footprint of a text editor?

    • The purpose of the share mode is to reuse objects and save memory, provided that the share object is immutable.
    • The definition of “immutable object” means that its state (the object’s member variables or properties) cannot be changed once it has been initialized through the constructor.
    • Code structure: its code implementation is very simple, mainly through the factory pattern, in the factory class, through a Map to cache the created share objects, to achieve the purpose of reuse.
    • The singleton pattern is applied to ensure that objects are globally unique. The application of share mode is to realize object reuse and save memory. The purpose of caching is to improve access efficiency, not reuse. The term “reuse” in pooling is understood as “reuse”, primarily to save time.
  56. Free element mode (part 2) : Analyzes the application of the free element mode in Java-INTEGER and String

    • In the Java Integer implementation, integers between -128 and 127 are pre-created and cached in the IntegerCache class.
    • In the implementation of the Java String class, the JVM dedicates a storage area for String constants called the String constant pool, similar to IntegerCache in Integer.
  57. Observer Mode (part 1) : Details the different implementations of the observer mode in various application scenarios

    • The creative design pattern mainly solves the problem of “object creation”, while the structural design pattern mainly solves the problem of “combination or assembly of classes or objects”

      Behavioral design patterns mainly solve the problem of “interaction between classes or objects”

    • Definition: Define a one-to-many dependency between objects. When an object’s state changes, all dependent objects are automatically notified

    • In general, the dependent object is called an Observable and the dependent object is called an Observer.

    • What design patterns do is decouple. The creative pattern decouples the code created and used, the structural pattern decouples the code of different functions, and the behavioral pattern decouples the code of different behaviors. Specifically, the observer pattern decouples the code of the observer and the observed

  58. Observer Mode (2) : How to implement an asynchronous non-blocking EventBus framework?

    • Synchronous blocking is the classic implementation, mainly for code decoupling; Asynchronous non-blocking can not only decouple code, but also improve the efficiency of code execution. The observer mode decoupling between processes is more thorough and is generally implemented based on message queues, which is used to realize the interaction between observed and observers between different processes.
    • The purpose of the framework is to hide implementation details, make development easier, reuse code, decouple business and non-business code, and let programmers focus on business development.
    • EventBus translated as “EventBus”
    • When the register() function is called to register an Observer, EventBus generates the Observer registry by parsing the @SUBSCRIBE annotation. When the POST () function is called to send a message, EventBus finds the corresponding function to receive the message through the registry, and then dynamically creates the object and executes the function using Java’s reflection syntax. For synchronous blocking, EventBus executes the corresponding functions sequentially within a thread. For asynchronous non-blocking mode, EventBus executes the corresponding function through a thread pool.
    • Many people think that doing business development has no technical challenges. In fact, doing business development also involves the development of many non-business functions, such as EventBus. In normal business development, we should be good at abstracting these non-business, reusable functions, and actively implement them into a general framework.
  59. Template pattern (part 1) : Analyze the application of template pattern in JDK, Servlet, JUnit, etc

    • The template pattern is mainly used to solve the problems of reuse and extension. Reuse refers to the fact that all subclasses can reuse the code of template methods provided in the parent class. Extension refers to the fact that the framework provides functional extension points through a template pattern, allowing framework users to customize the functionality of the framework based on extension points without modifying the framework source code.
    • The template method pattern defines an algorithm skeleton in a method and postpones some steps to subclasses. The template method pattern lets subclasses redefine certain steps in an algorithm without changing the overall structure of the algorithm.
  60. Template mode (part 2) : How is template mode related to the Callback function?

    • In terms of application scenarios, the synchronous callback is almost identical to the template pattern. They are all in a large algorithm skeleton, free to replace a certain step in the purpose of code reuse and extension. Asynchronous callbacks are different from the template pattern and more like the observer pattern.

    • In terms of code implementation, the callback and template patterns are completely different. Callbacks are implemented based on a combinatorial relationship, passing one object to another, a relationship between objects. The template pattern is implemented based on inheritance relationships, in which subclasses override the abstract methods of their parent classes.

  61. Strategic pattern (part 1) : How do I avoid lengthy if-else/switch branch determination code?

    • Definition: Defines a family of algorithm classes and encapsulates each algorithm so that they can be replaced with each other. Policy patterns can make changes to algorithms independent of the clients that use them (by client I mean the code that uses the algorithm)
    • Policy patterns: Definition, creation, and use of decoupled policies
  62. Strategy mode (below) : how to implement a support to different size file sort small program?

    • The main function of the policy pattern is to decouple the definition, creation and use of the policy, and control the complexity of the code, so that each part is not too complex and too much code. In addition, for complex code, the policy pattern also allows it to meet the open-closed principle, minimizing and centralizing code changes when adding new policies and reducing the risk of introducing bugs.
  63. Responsibility chain mode (I) : How to implement sensitive information filtering framework with flexible extension algorithm?

    • Decouple the sending and receiving of a request so that multiple receiving objects have the opportunity to process the request. These receive objects are strung together in a chain and the request is passed along the chain until one of the receiving objects on the chain can handle it.
    • There are two common implementations of the chain of responsibility pattern. One way is to use linked lists to store processors, another way is to use arrays to store processors, and the latter is simpler.
  64. Responsibility chain mode (2) : how are filters and interceptors commonly used in the framework implemented?

    • Responsibility chain mode is commonly used in framework development to realize the filter and interceptor functions of the framework, so that users of the framework can add new filter and interceptor functions without modifying the source code of the framework. This also reflects the design principle of being open for extensions and closed for modifications mentioned earlier.
  65. State patterns: How are state machines commonly used in games and workflow engines implemented?

    • Finite State Machine, English translation is Finite State Machine, abbreviated as FSM, abbreviated as State Machine. A State machine consists of three parts: states, events, and Actions. Events are also called transition-conditions. Events trigger transitions of state and execution of actions. However, the action is not required, and it is possible to just transfer the state without performing any action.

    • The state pattern avoids branching decision logic by splitting the event-triggered state transitions and action execution into separate state classes.

    • The state machine can be implemented in three ways:

      • The first implementation is called branching logic. Use if-else or switch-case branching logic to directly code each state transition exactly as it is, with reference to the state transition diagram. For simple state machines, this implementation is the simplest, most straightforward, and preferred.

      • The second implementation is called table lookup. For state machines with many states and complicated state transitions, table lookup is suitable. Representing state transition diagrams with two-dimensional arrays greatly improves the readability and maintainability of code.

      • The third implementation is called state mode. This is our preferred implementation for state machines where there are not many states and state transitions are simple, but the business logic involved in the actions triggered by the event may be complex.

  66. Iterator pattern (part 1) : What are the advantages of using iterators over directly iterating through collection data?

    • Three basic methods need to be defined in the iterator: hasNext(), currentItem(), and next(). The container object to be traversed is passed to the iterator class through dependency injection. The container uses the iterator() method to create iterators.

    • Three advantages of iterators

      • The iterator pattern encapsulates the complex data structure inside the collection. The developer does not need to know how to traverse, but can directly use the iterators provided by the container.

      • The iterator pattern separates the iterator operation from the collection class, making the responsibility of the two more single.

      • The iterator pattern makes it easier to add new traversal algorithms and is more open and closed. In addition, because iterators are implemented from the same interface, it becomes easier to replace iterators in development based on interface rather than implementation programming.

  67. Iterator mode (middle) : Why can’t collection elements be added or deleted while iterating through the collection?

    • The iterator pattern is used to decouple container code from traversal code
    • One is to not allow elements to be added or deleted during traversal, and the other is to allow traversal to report an error after adding or deleting elements. The first solution is more difficult to implement because it is difficult to determine when iterator use ends. The second solution is more plausible. The Java language uses this solution. After adding and deleting elements, we chose the Fail-fast solution, which allows the traversal operation to throw runtime exceptions directly.
  68. Iterator Mode (part 2) : How to design and implement an iterator that supports snapshots?

    • The container supports both quick traversal: in the container, two timestamps are stored for each element, one for adding timestamp and one for removing timestamp delTimestamp, and each iterator also holds an iterator for creating timestamp snapshotTimestamp

    • Let the container support both quick traversal and random access: you can store two arrays in an ArrayList. A support tag deletion, used to achieve the quick traversal function; One that does not support tag deletion (that is, the data to be deleted is removed directly from the array) and is used to support random access

  69. Visitor Patterns (part 1) : Walk you through the thought process that gave birth to the Visitor pattern

    • Most design patterns are simple in principle and implementation
    • Definition: Allows one or more operations to be applied to a group of objects, decoupling the operations from the objects themselves
    • In general, the visitor pattern targets a set of objects of different types (PdfFile, PPTFile, WordFile). However, although the types of these objects are different, they inherit the same parent class (ResourceFile) or implement the same interface. In different application scenarios, we need to carry out a series of unrelated business operations (text extraction, compression, etc.) on this group of objects. However, in order to avoid the expansion of classes (PdfFile, PPTFile, WordFile) with increasingly diversified responsibilities caused by constant addition of functions, and to avoid frequent code modifications caused by frequent addition of functions, Using the visitor pattern, we decouple the objects from the operations and isolate these business operations in a separate, segmented visitor class (Extractor, Compressor).
  70. Visitor Pattern (part 2) : Why do languages that support double dispatch not need the visitor pattern?

    • Visitor pattern: The code for this pattern is difficult to implement, so there are not many application scenarios
    • Single Dispatch refers to which object’s method executes, depending on the object’s runtime type; Which method of the object is executed depends on the compile-time type of the method parameter. Double Dispatch refers to which object’s method executes, depending on the object’s runtime type; Which method of the object is executed depends on the runtime type of the method parameter.
    • It is called “Double” because which method on which object is executed depends on the runtime type of both the object and the method parameter.
    • The visitor pattern mimics the implementation of DoubleDispatch with Single Dispatch
  71. Memo mode: How to optimize memory and time consumption for backup and recovery of large objects?

    • The application scenarios of the memo mode are also clear and limited. It is mainly used to prevent loss, cancellation, and recovery.
    • Definition: To capture the internal state of an object and store the state outside of the object so that the object can later be restored to its previous state without violating the encapsulation principle.
    • Backup of large objects consumes large storage space and takes a long time to back up and restore. Different business scenarios have different approaches to this problem. For example, back up only the necessary recovery information and restore it with the latest data. Another example is the combination of full backup and incremental backup, low frequency full backup and high frequency incremental backup.
  72. Command Mode: How to use command mode to implement a mobile game backend architecture?

    • Command mode, interpreter mode, mediation mode. These three patterns are used infrequently, difficult to understand, and only used in very specific application scenarios
    • Definition: The command pattern encapsulates a request (command) as an object, which can parameterize other objects with different requests (injecting different request dependencies into other objects), and supports queueing, logging, undo, and other (additional control) functions for requests (command).
    • The core implementation of the command pattern is to encapsulate functions as objects
    • A request sent from a client to a server usually consists of two parts: instructions and data. Where instructions can also be called events, data is the data needed to execute the instructions.
    • Every design pattern should be composed of two parts: the first part is the application scenario, which is what kind of problem the pattern can solve; The second part is the solution, that is, the design ideas and concrete code implementation of this pattern. We should focus more on application scenarios.
  73. Interpreter mode: How to design and implement a custom interface alarm rule function?

    • The interpreter pattern is more niche and is used only in specific areas such as compilers, rule engines, and regular expressions.
    • Definition: The interpreter pattern defines a syntactic (or grammatical) representation of a language and defines an interpreter to handle that syntax.
    • The core idea of its code implementation is to break parsing into smaller classes to avoid large, all-parsed classes. A common practice is to break the grammar rules into small, independent units, then parse each unit, and finally merge into the parsing of the whole grammar rule.
  74. Mediation patterns: When to use mediation patterns? When to use observer mode?

    • The mediation pattern is designed in much the same way as the middle layer, which transforms the interactions (or dependencies) between a set of objects from many-to-many (mesh) to one-to-many (star) by introducing a mediation.
    • Definition: A mediation pattern defines a single (mediation) object that encapsulates the interaction between a set of objects. Delegate the interaction between this set of objects to the mediation object to avoid direct interaction between objects.
    • Observer mode interaction is generally unidirectional, while intermediary mode interaction is complex
  75. Recommended books on design patterns, refactoring, programming specifications, etc

The last

If you like my article, you can follow my public account (Programmer Malatang)

My personal blog is shidawuhen.github. IO /

Review of previous articles:

Design patterns

  1. Go Design Pattern (5)- Class diagram symbolic representation
  2. Go Design Pattern (4)- Code writing optimization
  3. Go Design Pattern (4)- Code writing
  4. Go Design Patterns (3)- Design principles
  5. Go Design Pattern (2)- Object-oriented analysis and design
  6. Go Design Pattern (1)- Syntax

language

  1. Go tool generate
  2. Go singleton implementation scheme
  3. Implementation principle of Go channel
  4. Implementation principle of Go timer
  5. Beego framework use
  6. Golang source BUG tracking
  7. Gin framework concise version
  8. Gin source code analysis

architecture

  1. Payment access general issues
  2. Current limiting 2
  3. Seconds kill system
  4. Distributed systems and consistency protocols
  5. Service framework and registry for microservices
  6. Discussion on Micro-service
  7. Current limiting implementation 1
  8. CDN request process details
  9. Common Cache tips
  10. How to effectively connect with third-party payment
  11. Algorithm is summarized

storage

  1. MySQL development specification
  2. Redis implements distributed locking
  3. The implementation principle of atomicity, consistency and persistence of transactions
  4. InnoDB locks and transactions

network

  1. HTTP2.0 basics tutorial
  2. HTTPS Configuration Combat
  3. HTTPS Connection Process
  4. TCP Performance Optimization

tool

  1. Automatically generate go struct from mysql table
  2. Markdown editor recommends – Typora

Reading notes

  1. The principle of
  2. History As A Mirror
  3. Agile revolution
  4. How to exercise your memory
  5. Simple Logic – After reading
  6. Hot Wind – After reading
  7. Analects of Confucius – After reading
  8. Sun Tzu’s Art of War – Reflections from reading

thinking

  1. To mobilize all forces to fight for victory in the Anti-Japanese War
  2. Anti-liberalism
  3. practical
  4. The standard by which you judge yourself
  5. Service team holiday shift plan
  6. Project process management
  7. Some thoughts on project management
  8. Some thoughts on product manager
  9. Thinking about programmer career development
  10. Thinking about code review