This article is sponsored by Yu Gang Said Writing Platform

Original author: but qingmei smell

Copyright notice: The copyright of this article belongs to the wechat public account Yu Gangshuo

Art and

Data structure, algorithm and design patterns is considered to be one of the indispensable skill programmer trident, if the grammar of the programming language features and business ability is 【 】, so the three is [that] – [art] allows you to live in the IT industry, and [that] decide your future in technology on the road can walk far.

The dilemma of learning and forgetting

Let me introduce myself first.

I am an Android developer with two years of working experience. Just like many of my peers, I have hardly systematically studied data structure, algorithm and design pattern, which are regarded as the three internal skills required by programmers (data structure used to be specialized courses, but now I have basically returned it to teachers).

You asked me if I wanted to be a good programmer, of course! Data structures, algorithms and design patterns have been included in my learning plan for more than one time, which I think is meaningful and necessary, and I also try to learn them actively in my spare time.

Unfortunately, so far, I am still at the beginning stage of data structure and algorithm, for the following reasons:

I didn’t get a chance to use it for long, and then I forgot!

If you check out my previous blog posts or my Github repository, you’ll see that I’ve experimented with data structures and algorithms, but unfortunately I can’t put them to use — they just come and go, like people in my life.

As for design patterns, I don’t have much time to learn them in my spare time, and although I often study design patterns through blogs and books, the results haven’t changed much: the abstract concepts and infrequent use have made me forget them very quickly.

I found this method of learning not very efficient, so I decided to learn the design ideas and concepts by reading the source code of the open source library on Github.

motivation

Like most people, I’m just in many ordinary programming industry one of the developers, in the beginning of my career, I have no contact with technology, but reading source collision would it be possible for me to have a zero distance of the top engineers in the global industry, I think for me it is a good way to learn, let me benefit a lot.

In fact, WHEN I was writing this blog, I was still nervous. I was worried that if an article was not well written, it would mislead the reader.

I finally got up the courage to write this article because I wanted to share my personal understanding of design patterns, and my own learning style and gain. This learning style may not be suitable for everyone, but it can at least give a reference to those who need it.

Classification of design patterns

Let’s start with the classification of design patterns:

The scope of Create a type structured Behavior type
class Factory Method Adapter(Class) (Adapter) Interpreter (Interpreter)

Template Method
object Abstract Factory

The Builder

Prototype

Singleton (Singleton)
Bridge (Bridge)

A Composite

Decorator

Facade

Flyweight

Proxy
Chain of Responsibility

I can’t Command you.

An Iterator.

Mediator

Memento

An Observer

State (body)

Strategy

Visitor (Visitor)

This is a summary of design patterns THAT I found in this article.

At the same time, we need to understand the six basic principles of design patterns (listed here and explained in case studies) :

  • Single Responsibility Principle
  • Liskov Substitution Principle
  • Dependence Inversion Principle
  • Interface Segregation Principle
  • Demeter Principle, also known as Demeter Principle
  • Open Close Principle

In the process of learning design patterns, these design patterns are not explained step by step according to different types, but more scenes are composed of multiple different types of design patterns — the final display is a complete architectural design system. The benefits of this complex combination of design patterns are high cohesion and low coupling, which makes it easy to expand the library itself, as well as easy to unit test.

For through the source code, of course, want to catch a glimpse of design thought to learners, additional interfaces, and then the forehead to extra code may need more learning cost, for the initial me, complex design really brings me a lot of trouble, I’m trying to understand and reflect on the benefits of this design – it took me more time, But I benefited a lot more.

Initial takeaways — the creation pattern

In the process of learning Android, I first came into contact with the creation mode, the so-called creation mode, naturally related to the creation of objects.

In fact, apart from source code, we have encountered many examples of the creation pattern in actual development, the most common being singleton pattern and Builder pattern.

1. The “simplest” design pattern

Let’s take the singleton pattern as an example, which is defined as:

“A class has one and only one instance, and its own instantiation is provided to the entire system.”

Known as “one of the simplest forms of design patterns,” the singleton pattern is simple and easy to understand, and developers often encounter business requirements that require them to hold unique objects.

In Android development, for example, we often need to use an Application object in a class that is unique in itself, so we just need to hold a static reference to it through a class and get it through a static method.

Another requirement is that objects of a certain class take up a lot of memory, and there is no need to instantiate the class twice. In this way, more performance space can be saved by keeping the class singleton of its objects, such as the reference of the Android database DB.

In fact, there are many implementations of singleton pattern subdivided, such as the well-known lazy, Double CheckLock, static inner class, enumeration, these different singleton implementation, have their own advantages and disadvantages (such as whether thread safety), but also corresponding to different scenarios. This is why the singleton appears to be the “easiest” and is the most important item to examine during the interview.

These different implementation methods, Baidu explained very detailed, this article does not repeat.

What we need to understand is when we use the singleton pattern.

For some classes in the system, it is understandable that only one instance is important, such as the Application mentioned above. In fact, during the development process, we need to pay more attention to the implementation of some details.

Such as the singleton for Gson.

In real development, there are so many places where a Gson object is called for transformation that it can affect performance if a new Gson is called every time.

Gson itself is thread-safe and can be used by multiple threads at the same time, so I prefer to get an instance of Gson as follows:

public class Gsons {

    private static class Holder {
        private static final Gson INSTANCE = new Gson();
    }

    public static Gson getInstance(a) {
        returnHolder.INSTANCE; }}Copy the code

Not only Gson, but also related management classes for network requests (Retrofit objects, ServiceManager, etc.), various XXXManager (NotificationManager) provided by Android system, etc., which manage it by singleton way. Can make your business design more rigorous.

2. Chain call of Builder

The Builder Pattern uses multiple simple objects to build a complex object step by step.

Android developers must be familiar with it, because when we created AlertDialog, the chain-call API was pretty pleasing:

new AlertDialog
   .Builder(this)
   .setTitle("Title")
   .setMessage("Content")
   .setNegativeButton("Cancel".new DialogInterface.OnClickListener() {
       @Override
       public void onClick(DialogInterface dialog, int which) {
            / /...
       }
   })
   .setPositiveButton("Sure".new DialogInterface.OnClickListener() {
       @Override
       public void onClick(DialogInterface dialog, int which) {
            //....
       }
   })
   .create()
   .show();
Copy the code

The append() method used in the StringBuilder and StringBuffer source code in the JDK also represents the Builder mode:

public StringBuilder append(String str) {
        super.append(str);  // Call the base class append method
        return this;
}

// Base class append method
public AbstractStringBuilder append(String str) {
       if (str == null) str = "null";
       int len = str.length();
       ensureCapacityInternal(count + len);
       str.getChars(0, len, value, count);
       count += len;
       return this; // Returns the build object
}
Copy the code

In addition to the beautiful code, I was more concerned with the usage scenarios of Builder mode:

When we are faced with the creation of a complex object, it is usually composed of sub-objects of each part with a certain algorithm. The pieces of this complex object often face drastic changes due to changing requirements, but the algorithms that put them together are relatively stable.

Good, I copied the Builder model from this learning site. I tried to understand its narrative while learning it, and came to the conclusion that the above definition is very strict, but I don’t understand it.

We refer to AlertDialog. For a Dialog, its basic composition is complex (title, content, buttons and their corresponding events, etc.), but in practice, different interfaces need to present different dialogs to users (title, content, etc.). Click events are also different), these parts are constantly changing dramatically, but their combination is relatively stable (i.e., a Dialog pops up on the screen).

In this case, we can try using Builder mode. Unlike normal constructor objects, we can ignore to configure certain properties if there is no need — for Dialog, I can not define the title, I can not define the cancel button click event, both of which have default handling internally; In addition, for API design, Builder mode is more convenient to extend new functions or attributes.

The Builder pattern is very common in our development, as well as Android’s popular image-loading library, instantiation of Notification notifications, and more.

As mentioned above, The Builder pattern provides a very pleasing API for object creation. After I understood the idea and implementation of the Builder pattern, I tried to add some of these designs to some of my own tool classes.

Soon, I ran into a problem, and that was — it was fucking tiring!

3. Avoid over-designing

For a definition of overdesign, see What is Overdesign in Software Development? I think the explanation is very interesting and easy to understand.

From my personal point of view, I ran into problems. I tried to convert some tools to Builder implementations, and as a result, I added lots and lots of code, but the results were mediocre.

Not only that, but it also added complexity to my tools, requiring many lines of chain-configuration to solve problems that could be solved by a single constructor.

As a result, I agree with the conclusion made by an elder on the Internet, that is:

An important role of design patterns is code reuse, the ultimate goal is to improve efficiency. So, whether a pattern is appropriate or necessary is to see if it can reduce our work and improve our work efficiency.

So, how to avoid over-design, my experience tells me to think before you write code, consider the cost of different implementations, and make sure your code is constantly iterating and tweaking.

Even so, in the process of development, over-design is still an inevitable situation, only to rely on the accumulation of experience and continuous summary thinking, slowly adjust and enrich their own personal experience.

4. Single responsibility and dependency injection

With the singleton pattern, I also seem to run into the problem of over-designing — it seems too cumbersome to write another class to encapsulate every singleton of an object.

In fact, this is not overdesign, as it is necessary and saves on performance, but object creation and management is still a significant amount of work for developers.

In addition, it is important to consider that a complex singleton may have many states and dependencies, which means that the singleton class is likely to be heavily responsible, somewhat violating the singleton responsibility principle:

A class is responsible for only one function area, or can be defined as: in the case of a class, there should be only one cause for its change.

The single responsibility principle tells us that a class can’t be too “tired”! The more responsibility a class has (often reflected in the dependencies required by the constructor), the less likely it is to be reused.

Once we understand the advantages and disadvantages of the singleton pattern, we can choose to use the singleton pattern, but we need to carefully consider the singleton pattern that relies on overly complex objects.

For complex dependency management, a dependency injection library such as Dagger is an option (seriously). For a Singleton implementation, just add a @Singleton annotation on the corresponding dependency Provider in your Module and the compiler will automatically generate the corresponding Singleton code for you at compile time.

Admittedly, this tool has a relatively high learning cost, but once you learn dependency injection tools and understand the ideas of IOC(Inversion of Control) and DI(dependency injection), it can be a powerful tool in your development process.

5. Open and close principle

The Open closed principle: software should be open for extension and closed for modification. In the words of Head First, code should be closed like a lotus in the sunset (free from change) and open like a lotus in the morning (able to expand).

The Builder pattern is the full embodiment of the open closed principle. It isolates the construction and invocation of objects, so that different users can freely build objects and then use them.

6. Summary

Create mode is the most easy to entry, because this type of model, more often exposed to developers in front, but they are not simple, except that the patterns we use way, more should be thinking about when to use, with which, even use a combination of them – they are incompatible, some can be complementary, this needs us to study some of the more classical code, And try it yourself.

Not only creative, but also structural and behavioral design patterns that follow, this article will not cover all of the design patterns in its catalog.

Structural mode

Definition 1.

First, the definition of structural patterns in the book is described:

The structural pattern deals with how to combine classes and objects to achieve a larger structure. The structural class pattern uses inheritance mechanisms to compose interfaces or implementations.

At the beginning of the study, for me personally, read the design patterns: elements of reusable object-oriented software just like read manuals, the content of the book of each design pattern has carried on the detailed explanation, but after I finish reading, soon forgotten, or to look very similar to two kinds of design patterns wondering – explain detail in the book, but it’s too abstract.

Ultimately (and now), my personal understanding of the structural pattern is to implement new functionality by combining different classes or objects, by inheriting or combining interfaces, or by combining objects.

In one sentence, it is a way of implementing combinatorial scheduling between objects with different responsibilities (in the form of objects/abstract classes/interfaces).

2. Not all object combinations are structural patterns

In fact, not all of the combination of the object belongs to the structural model, configuration model is that the significance of combination of some object, in order to realize the new functions, by running, by changing the composition, the relationship between the flexibility to produce different effect, this mechanism, common object composition is impossible.

Next, I will deepen my understanding of the above statement by illustrating the application of several different structural patterns in practical development.

3.RecyclerView: Adapter mode

RecyclerView is the preferred solution to realize lists in Android daily development. From my perspective, I haven’t figured out a problem: how to realize lists in RecyclerView?

RecyclerView Adapter can be used to create lists.

In fact, yes, but it raises another question, what is the relationship between Adapter and RecyclerView, why can you implement Adapter and RecyclerView?

Consider a real problem: I have a laptop and I have a power source in my house. How do I charge my laptop?

Without thinking, we used the laptop charger to connect the power source to the laptop. In fact, the charger is more officially called an Adapter. There is no direct relationship between the laptop and the power supply, but through the Adapter Adapter, they can generate a new function — the power supply to charge the laptop.

RecyclerView and data display are the same. There is no direct relationship between data objects and RecyclerView, but if I want to display data in RecyclerView, I can configure an Adapter for RecyclerView to connect to the data source.

Now let’s look at the Adapter pattern definition:

Make classes that would otherwise not work together due to interface incompatibilities work together.

Now that we understand how the adapter pattern works, I want to throw out a question:

Why do I implement an Adapter, why can’t I just create RecyclerView?

For example, since I have a data source, why can’t RecyclerView be configured directly like this at the beginning of design?

mRecyclerView.setDataAndShow(datas);
Copy the code

My understanding is that, if RecyclerView is compared to the power socket in the house, the power does not know what device it will connect to (also, RecyclerView cannot know what kind of data it wants to display and how to display it), and the interface of different devices may be different, but as long as a corresponding adapter is configured for the device, Two unrelated interfaces can work together.

RecyclerView designers will realize hidden to developers, and through Adapter to developers exposed its interface, developers through the configuration of data sources (equipment) and the corresponding Adapter (charger), can realize the list of display (charging).

Retrofit: Appearance patterns and dynamic proxies

Speaking of Demeter’s law (also known as the least knowledge principle), this should be easy to understand, reducing the coupling between modules:

Demeter’s Law: a software entity should interact with as few other entities as possible.

One of the first libraries I learned that showed me the beauty of combining design patterns was Retrofit, where for network requests you only need to configure one interface:

public interface BlogService {

    @GET("blog/{id}")
    Call<ResponseBody> getBlog(@Path("id") int id);
}

// The usage mode
// 1. Initialize the Retrofit object
Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("http://localhost:4567/")
        .addConverterFactory(GsonConverterFactory.create())
        .build();
Instantiate the BlogService interface
BlogService service = retrofit.create(BlogService.class);
Copy the code

The source code for Retrofit is a combination of design patterns applied together to form a framework that guarantees what we call high cohesion and low coupling, and is a good example of design pattern learning, as shown below:

When analyzing the overall framework, we start with how the API is used, and we can see that when configuring Retrofit, the library adopts facade mode as the facade of Retrofit.

A friend said, in my opinion, shouldn’t Retrofit initialization be Builder mode? Why do you call it appearance mode?

Let’s start by looking at the definition of appearance patterns in Design Patterns: The Foundation of Reusable Object-oriented Software:

To provide a consistent interface for a set of interfaces in a subsystem, the facade defines a high-level interface that makes the subsystem easier to use.

My interpretation is that Retrofit, a network request library, has many different components inside, including data serialization, thread scheduling, different adapters, etc. A series of complex subsystems are indispensable and complicated for network requests. So, By handing them all over to a Retrofit object to configure and schedule (the Creation of the Retrofit object is, of course, implemented through the Builder pattern), the configuration is easy and convenient to use for API callers, as defined by the appearance pattern.

Having briefly understood the idea of appearance patterns, let’s take a look at dynamic proxies. One of the hardest things for me to understand when I was first introduced to Retrofit was how Retrofit helped me create a Service object with only one interface configured.

Instantiate the BlogService interface
BlogService service = retrofit.create(BlogService.class);
Copy the code

In fact, there is no BlogService object created. The Service is just a proxy object dynamically generated at JVM runtime. The meaning of this proxy object is:

Provide a proxy for other objects to control access to that object.

I want to make a web request through BlogService, and Retrofit will implement a proxy object through dynamic proxy that acts as a proxy for BlogService, and when I call one of its methods to make a web request, it’s actually the proxy object that parses your annotations and method parameters, The OkHttpCall object is wrapped as a network request through a series of logic and requests the network.

Now I see, no wonder Retrofit generates proxy objects dynamically and parses them when calling its methods, no matter what I name the Service’s interface or method, which is perfect for complex and variable network requests.

5. Richter’s substitution principle

In the excellent source code, we can often see that many functions are implemented by relying on their interfaces. Here we must first understand one of the most important basic principles in object orientation, the Richter substitution principle:

Wherever a base class can appear, a subclass must appear.

Richter’s substitution principle is a complement to the open – close principle. The key step in implementing the open close principle is abstraction. The inheritance relationship between base class and subclass is the concrete realization of abstraction, so the Richter substitution principle is the specification of the concrete steps to realize abstraction.

Upscaling is fundamental to Java, and we use it a lot. In fact, when designing, try to inherit from abstract classes, not concrete classes. At the same time, it is sufficient to ensure that in the software system, the behavior of the program does not change when the parent class is replaced by its subclasses.

6. Summary

Through the above cases, we simply understand the concepts and ideas of several structural design patterns and summarize them as follows:

After solving the problem of object creation, the composition of objects and the dependency between objects has become the focus of developers, because how to design the structure, inheritance and dependency of objects will affect the maintenance of subsequent programs, code robustness, coupling and so on. So there are multiple structural patterns that developers can choose from.

Improve collaboration efficiency between classes — behavioral patterns

Definition 1.

Let’s start with a more rigorous definition of behavioral patterns in the book:

Behavior patterns are concerned with the assignment of responsibilities between algorithms and objects. Behavior patterns not only describe the patterns of objects or classes, but also describe the communication patterns between them. These patterns delineate complex control flows that are difficult to track at runtime, shifting your focus from control flows to how objects are connected.

Still a little hard to understand, let’s take two examples:

OkHttp: Intercepter and Responsibility chain mode

In Okhttp, the Intercepter is a typical example of the chain of responsibilities pattern. It can set up any number of intercepters to do any intermediate processing for network requests and their responses — setting up caching, Https certificate validation, unified request encryption/anti-string modification, printing custom logs, filtering requests, etc.

new OkHttpClient.Builder()
              .addNetworkInterceptor(interceptor1)
              .addNetworkInterceptor(interceptor2)
              .addNetworkInterceptor(interceptor3)
Copy the code

The chain of responsibility mode is defined as:

Avoid coupling between the sender and receiver of the request by giving multiple objects a chance to process it, link them together in a chain, and pass the request along the chain until an object handles it.

Take reality as an example, one of the responsibility chain modes is network connection. The network connection model of seven or five layers is as follows:

  • The network request goes through the application layer -> Transport layer -> network layer -> Connection layer -> physical layer

  • After receiving the response, the physical layer goes to the connection layer, network layer, transport layer, and application layer

Each layer takes turns processing the request as it passes through the layers. Each layer can handle requests or responses. And you can break the link and return the response with itself as the end point.

3.RxJava: Observer mode

In Android development, the monitoring of click events is the embodiment of the classic observer mode:

button.setOnClickListener(v -> {
    // do something
})
Copy the code

For OnClickListener, the View is the observed and OnClickListener is the observer, and the two are registered (subscribed) through the setOnClickListener() method. Once subscribed, when the user clicks the button, the View sends the click event to the OnClickListener that has been registered.

Also, for RxJava, which is compatible with Retrofit, it is implemented through the Observer pattern.

// Observed
Observable observable = Observable
                          .just("Hello"."Hi"."Aloha")

/ / observer
Observer<String> observer = new Observer<String>() {
    @Override
    public void onNext(String s) {
        Log.d(tag, "Item: " + s);
    }

    @Override
    public void onCompleted(a) {
        Log.d(tag, "Completed!");
    }

    @Override
    public void onError(Throwable e) {
        Log.d(tag, "Error!"); }};// Execute the subscription relationship
observable.subscribe(observer);
Copy the code

RxJava’s powerful asynchronous processing divides the creation and reception of data into two parts. To the observer, it does not care about when or how data is transmitted. It only cares about what happens when the latest data is observed.

Now that we know about the observer mode, we need to think deeply about the influence of the observer mode on our code design system — what are its benefits?

The most immediate benefit is that the observed does not know the detailed implementation of the observer.

As I just said, the observed is only responsible for emitting the event, and it doesn’t care how the event is handled, which means that the observed and the observer are not tightly coupled, they can be at different levels of abstraction in a system.

For example, a Button click event is a library tool that belongs to the bottom component of the project. For a Button click event, it belongs to the top layer of the business code. Buttons and click events are not at the same level of abstraction, and a Button at a lower level can send click events to and notify event listeners at a higher level.

Otherwise, the observer and the observed would have to be mixed together so that the object would traverse both levels of the project (violating hierarchy), or it would have to be placed in one of the two levels (potentially compromising hierarchy abstraction).

The dependency inversion principle is easy to understand when you understand the benefits of abstracting the behavior of the bottom component after the button is clicked and delegating it to a higher level.

4. Dependency inversion principle

Now let’s look at the dependency inversion principle:

Abstraction should not depend on details, details should depend on abstractions. In other words, program for the interface, not the implementation.

Its principles are:

  • 1. High-level modules should not depend on low-level modules, both should depend on abstractions.
  • 2. Abstraction should not depend on details. Details should depend on abstractions.

In Java, abstraction refers to an interface or abstract class, and details are concrete implementation classes. The purpose of using interfaces or abstract classes is to create specifications that do not involve any concrete operations, leaving the task of presenting details to their implementation classes.

Knowing the dependency inversion principle, let’s go ahead and learn the last basic design pattern principle:

5. Interface isolation principle

Interface isolation principle: a client should not rely on interfaces it does not need; The dependency of one class on another should be based on the smallest interface.

This is probably the best understood principle, which means that it is better to have multiple specialized interfaces than to have a single master interface.

For Bird, we can define two functional interfaces, namely Fly and Eat. We can make Bird implement these two interfaces respectively — if we have a Dog, then we can reuse the Eat interface, but if there is only one interface (including Fly and Eat), For Dog, it can’t Fly, so you need to declare a new interface for Dog, which is unnecessary design.

6. Summary

After the structure of the object and the creation of the object are solved, the behavior of the object remains. If the behavior of the object is well designed, the behavior of the object will be clearer and the efficiency of collaboration between them will be improved.

Now let’s look at the more rigorous definition of behavioral patterns in the article, I believe you can understand some:

Behavior patterns are concerned with the assignment of responsibilities between algorithms and objects. Behavior patterns not only describe the patterns of objects or classes, but also describe the communication patterns between them. These patterns delineate complex control flows that are difficult to track at runtime, shifting your focus from control flows to how objects are connected.

To catch my breath

This is basically the end of the discussion about design patterns.

And so on…

I haven’t learned a single design pattern, and you’re fucking telling me you’re done?

Nothing?

This article does not go through the code simply described each design pattern is implemented, means nothing to me, design thought is through constantly thinking, to understand and learn to try, in a short time fast reading lots of little effect, even learned how to make the sample of the design idea, into a complex business in the actual product design, This is also a very big problem.

Here, I quote one of my favorite classic moments from “Lean on Heaven and Slay Dragon”, which is when Zhang Sanfeng taught Zhang Wuji the taiji sword in front of the enemy on Wudang Mountain.

Zhang Sanfeng asked, “Boy, do you see this clearly? ‘Zhang Wuji said,’ See clearly. ‘Zhang Sanfeng said,’ Do you remember everything? ‘Zhang Wuji said,’ I have forgotten half of it. ‘Zhang Sanfeng said:’ Ok, that’s difficult for you. Go figure it out for yourself. ‘Zhang Wuji bowed his head and mused. After a while, Zhang Sanfeng asked, ‘What’s going on now? ‘Zhang Wuji said,’ I have forgotten most of it. ‘

Zhou Dian lost her voice and cried, “No! More and more forgotten. Zhang zhenzhen, you this road swordsmanship is very abstruse, see how can remember? Please show it to our Lord once more. ‘

Zhang Sanfeng smiled and said, ‘Ok, I’ll do it again. ‘Bring up your sword and play. The people only looked at a few moves, and were surprised to find that the second move was not the same as the first one. “Terrible, terrible!” cried Britain. This is all the more bewildering. ‘Zhang Sanfeng drew his sword in a circle and asked,’ Boy, what’s going on? ‘Zhang Wuji said,’ There are still three moves I haven’t forgotten. ‘Zhang Sanfeng nodded and returned to his seat.

Zhang Wuji paced slowly around the hall for a long time. After a long time of meditation, he paced slowly around half a circle, raised his head, and exclaimed with a happy face, ‘I have forgotten all about it. ‘Zhang Sanfeng said,’ Neither bad nor bad! Forget so fast, you now ask the eight-armed sword for advice! ‘

conclusion

As for the design pattern, my understanding is not to stick to its concept, but to have a deep understanding of its design idea, and then try to use it personally. In the process of use, I think it will be better to deepen the understanding of this idea than to learn it one by one through books or blogs.

I learned them by studying the source code of some good open source libraries, thinking about why these design patterns are used here, then referring to the concepts in the book Design Patterns, and finally trying and understanding them myself.

To me, this way the board is in the beginning, may need more time to study, many library source code in the first contact, not easy to understand, but the advantage is that after the society, the idea is hard to run away from your memory, and, when writing code, unconsciously try to use these patterns (of course, more is open two Windows, Reference source code while learning to incorporate it into your own code).

Design pattern relative to the classification and concept as tai chi chuan (sword), it is an idea, a response to the change of address thought – I don’t think his way of learning and experience, this paper can be suitable for each and every one is reading this article, but if this paper do you have some help for technical path of growth, for me it was worth it.

reference

1. The novice tutorial – design patterns: http://www.runoob.com/design-pattern/design-pattern-tutorial.html

2. “Design Patterns: The Foundation of Reusable Object-oriented Software”, Gamma, et al. Translated by Li Yingjun et al., China Machine Press, The 37th printing of the first edition in December 2015

3. The Retrofit analysis – beautiful decoupling format: https://blog.piasy.com/2016/06/25/Understand-Retrofit/

4. Create a model, the relationship between the structural model and the model of behavior, https://blog.csdn.net/qq_34583891/article/details/70853637

Welcome to follow my wechat public number, receive first-hand technical dry goods