My Simple Book: Remembering 23 Design Patterns from Android Code

I’m sure you’ve all made up your mind to memorize these 23 design patterns, only to forget them later and have to go back to them again. The only thing you can vaguely remember are the rough definitions of a few design patterns. In fact, many articles on the Internet are very good, AND I have read various articles. I have been distressed that these design patterns are hard to write down forever, until I came into contact with the “Android source code design pattern analysis and combat” — He Honghui and Love Ming, found that in fact we have been in contact with these design patterns in Android, but we do not know it. Now that we’ve all done it, we just need to remember design patterns one by one. Here voluntary free to do an advertisement, “Android source code design pattern analysis and actual combat” this book is really good, every Android programmer had better go to read… As you might expect, this article is a summary of the book, and I’m sure you’ll benefit as much as I do.

First, why do we learn design patterns? The main is that these patterns are the experience summarized by predecessors, using these patterns can make our program more robust, more stable, easy to expand and so on. When writing object-oriented programs, we need to follow the following six principles to make our programs easier to maintain (among other benefits).

1 The single responsibility principle The single responsibility principle is simply to encapsulate a set of highly related functions and data into a class. In other words, a class should have a single responsibility.

2 open and close principle

The open closed principle is also not complicated to understand, namely that a class should be open for extension but closed for modification. As we know, in the open app or system, it is often necessary to upgrade and maintain, which requires modifying the original code, but the modification is easy to destroy the original system, and even bring some new bugs that are hard to find. Therefore, when we start writing code, we should be careful to implement new functionality by extending it rather than modifying existing code.

Richter’s substitution principle

The Richter substitution principle is defined as: all references to a base class must be able to transparently use its subclass objects. The definition looks abstract, but it’s easy to understand, and it basically says, take advantage of inheritance and polymorphism. Simply put, a variable (or parameter) declared as a parent class is assigned to any subclass that inherits from that parent class without affecting program execution. You can see this principle by looking at a set of code:


public class Window(){
    public void show(View child){
        child.draw();
    }
}
public abstract class View(){
    public abstract void draw();
    public void measure(int widht,int height){
        
    }
}
public class Button extends View{
    public void draw(){
        
    }
}

public class TextView extends View{
    public void draw(){
        
    }
}Copy the code

The Window class shows the View and calls the draw function of the View object. Every subobject that extends from View has an implementation of Draw. There is no subclass that extends from View but does not implement the draw function. We use The Richter substitution principle in abstract class design.

4 Dependence inversion principle

Dependency inversion is mainly to achieve decoupling, so that high-level modules are not dependent on the implementation details of low-level modules. To understand it, we need to know a few key points:

(1) high level modules should not depend upon low level modules (implementation), both should depend upon abstractions (abstract class or interface) (2) the abstractions should not depend upon details (bs, abstract classes and interfaces must not depend on the specific implementation) (3) details should depend upon abstractions (same crap, specific implementation class must be dependent on the inheritance of the abstract class or interface)

In fact, in the Java language we use, abstraction is either an interface or an abstract class, neither of which can be instantiated directly; Details are the implementation classes, the classes that implement interfaces or inherit abstract classes. Using the Java language, the description is simple: the parameters passed between modules are declared as abstract types, rather than concrete implementation classes.

5 Interface isolation rules

The interface isolation principle defines that dependencies between classes should be established on the smallest interface. The principle is to break up very large, bloated interfaces into smaller, more specific ones.

6 Demeter principle

Principle of description: One object should know the least about other objects. What does that mean? That is, a class should know the least about the class it calls. Still don’t understand? To put it simply: Suppose class A implements A function, and class B needs to call class A’s to perform the function, then class A should expose only one function to class B, which represents the function that implements the function, rather than having class A expose all the subdivided functions that implement the function to class B.

After learning the above six principles, do the preheating in advance. Let’s learn about design patterns

1 Singleton mode

The singleton pattern is arguably the easiest to understand and one of the most widely used, so let’s start with the definition.

Definition: Ensures that a singleton class has only one instance, and that the singleton class provides a function interface for other classes to get that unique instance.

When to use the singleton pattern: if a class takes a lot of resources to create, that class is expensive to new; Or the class takes up a lot of memory. Creating too many instances of this class will result in too much memory.

While the singleton pattern is simple and doesn’t require much explanation, it’s worth noting that there are many holes in the singleton pattern. Let’s go to the singleton pattern. The simplest singleton pattern is as follows:

public class Singleton{ private static Singleton instance; private Singleton(){}; public static Singleton getInstance(){ if(instance==null) instance=new Singleton(); return instatnce; }}Copy the code

If you’re on a single-threaded system, this is fine. But what about multithreaded environments? This code is obviously not thread-safe and has some pitfalls: a thread could getInstance null, which you might think would be a big deal if you simply added the sychronized keyword to getInstance(). But did you realize that synchronization is performed every time getInstance() is called, which incurs an unnecessary performance cost? Note that when the sychronized keyword is added to a method, when one thread accesses the method, other threads cannot simultaneously access the sychronized methods of the class. Let’s look at another implementation:

public class Singleton{
    private static Singleton instance;
    
    private Singleton(){};
    public static Singleton getInstance(){
        if(instance==null){
            sychronized(Singleton.class){
                if(instance==null)
                    instance=new Singleton();
            }
        }
        return instatnce;
    }
}
Copy the code

Why do you need two checks to see if it’s empty? The first determination is to avoid unnecessary synchronization, and the second determination is to ensure that no other threads have entered the Sychronized block before creating a new instance. This code looks perfect, but there are pitfalls! What’s the problem? Instance =new Singleton(); This code right here. This code compiles into multiple instructions and roughly does three things:

(1) Allocate memory for Singleton instance (2) call Singleton() constructor to initialize member field (3) point instance to allocated memory (instance is not null)

The order of (2) and (3) above is not guaranteed, that is, the JVM may first initialize instance fields and then refer instance to a specific memory instance, or it may first refer instance to a memory instance and then initialize instance member fields. In general, these two methods will not affect the correct execution of the program, but will affect the above singleton code. On the second check for instance null, we might have instantiated it in memory, missing step (3), but our check is still true, causing the thread to new a Singleton object the next time. Look at another way:

public class Singleton{
    private volatile static Singleton instance;
    
    private Singleton(){};
    public static Singleton getInstance(){
        if(instance==null){
            sychronized(Singleton.class){
                if(instance==null)
                    instance=new Singleton();
            }
        }
        return instatnce;
    }
}Copy the code

The volatile keyword is used to fetch the latest data from the heap every time a thread uses a volatile variable. In other words, every time an instance is used, it is guaranteed to be up to date. Note: The volatile keyword does not solve the concurrency problem. See other articles on volatile. But volatile would solve our problem here.

So where do you use singletons in Android? The Binder object we get when we call the system service is a singleton. Such as:


WindowManager wm = (WindowManager)getSystemService(getApplication().WINDOW_SERVICE);  
Copy the code

Internally, it is returned in the form of a singleton, which is not explored here because of the simplicity of the singleton pattern.

2 Builder pattern

What about Builder mode? I don’t want to mention its definition, because its definition is to separate the construction of a complex object from its representation so that the same construction process can create different representations. Okay, I’ll bring it up anyway. But there’s nothing luan can do with this definition. Let’s see when we use the Builder mode: when we create an object, we need to set a lot of parameters (via setter methods), but these parameters must be set in a certain order, or the setting steps will get different results. Here’s a very simple example:

public class MyData{ private int id; private String num; public void Test(){ } public void setId(int id){ this.id=id; } public void setNum(String num){ this.num=num+"id"; }}Copy the code

Of course, no one would write code that way. This is just an example, or sometimes there are too many arguments through the constructor when many arguments have similar dependencies. Back to the point, what if it was the code above? Well, you might say, well, that’s not easy, call setId, call setNum. Yes, that’s right. But what if you accidentally call setNum first? This is a simple example, but if it is a complex one with many dependencies between variables, you have to be careful to write the steps of each function correctly every time. Let’s see how Builder mode works:

public class MyBuilder{ private int id; private String num; public MyData build(){ MyData d=new MyData(); d.setId(id); d.setNum(num); return t; } public MyBuilder setId(int id){ this.id=id; return this; } public MyBuilder setNum(String num){ this.num=num; return this; } } public class Test{ public static void main(String[] args){ MyData d=new MyBuilder().setId(10).setNum("hc").build(); }}Copy the code

Note that setter functions of the Builer class return their own reference to this, which is mainly used for chain calls, and this is an obvious feature of the Builder design pattern.

Android used code to remember

Memorizing my example doesn’t make much sense, as we said earlier, it’s about memorizing code from Android so you don’t have to memorize it by rote. So where is the Builder design pattern used in Android? When creating a dialog box, is it similar to the above?

AlertDialog.Builer builder=new AlertDialog.Builder(context);
builder.setIcon(R.drawable.icon)
    .setTitle("title")
    .setMessage("message")
    .setPositiveButton("Button1", 
        new DialogInterface.OnclickListener(){
            public void onClick(DialogInterface dialog,int whichButton){
                setTitle("click");
            }   
        })
    .create()
    .show();Copy the code

The create() function here is reminiscent of the build function in the code above. See here is not the heart of the Builder design mode quietly down? You don’t have to memorize

3 Prototype Mode

The prototyping pattern is very simple: copy an object. For instance A of class A, to copy A is to create an instance B of type A, which is the same as A, and then copy all the attributes of A to B. When do you use prototype patterns? Personally, I think you can use the prototype pattern when the class has a lot of attributes, but you need to copy the class frequently, so the code is simpler and more convenient.

Also note that there are deep and shallow copies. Deep copy refers to making a copy of the referenced object within the object and referring to the new referenced object as the copied object. Said more around ha ~, for example, assume that have A class B reference class A, B, now need to copy of A class instance, then deep copy is, to make A copy for nb, B then the nb as A class A copy of the object reference, so one layer iteration copy, copy all references to an end. Shallow copies are not.

The prototype mode is relatively simple. Let’s see how Android uses the prototype mode:

Uri uri=Uri.parse("smsto:10086");
Intent shareIntent=new Intent(Intent.ACTION_SENDTO,uri);


Intent intent=(Intetn)shareIntent.clone();
startActivity(intent);
Copy the code

We might not normally write it this way, but Intent objects do provide the prototype-mode function Clone ().

4. Factory method mode

Define: Define an interface for creating objects, and let subclasses decide which class to instantiate first.

public abstract class Product{ public abstract void method(); } public class ConcreteProductA extends Prodect{public void method(){system.out.println (" ConcreteProductA extends Prodect! ); }} Public class ConcreteProductB extends Prodect{public void method(){system.out.println (" ConcreteProductB extends Prodect! ); } } public abstract class Factory{ public abstract Product createProduct(); } public class MyFactory extends Factory{ public Product createProduct(){ return new ConcreteProductA(); }}Copy the code

Looking at the code above, does factory mode seem simple? ConcreteProductA or ConcreteProductB can also be created by passing a parameter to the createProduct method of MyFactory based on the parameter passed in.

Again, we don’t want to remember this example, but rather remember it from the code in Android: In getSystemService, the factory mode is used, which is used to determine which object to create based on the parameters passed in. Of course, since the singleton is returned, it is not new.

public Object getSystemService(String name) {
    if (getBaseContext() == null) {
        throw new IllegalStateException("System services not available to Activities before onCreate()");
    }
    
    if (WINDOW_SERVICE.equals(name)) {
         return mWindowManager;
    } else if (SEARCH_SERVICE.equals(name)) {
        ensureSearchManager();
        return mSearchManager;
    }
    
    return super.getSystemService(name);
  }
Copy the code

Abstract factory pattern

Abstract Factory pattern: Provides an interface for creating a set of related or interdependent objects without specifying their concrete classes. Compare this to the factory method pattern:

public abstract class AbstractProductA{ public abstract void method(); } public abstract class AbstractProdectB{ public abstract void method(); } public class ConcreteProductA1 extends AbstractProductA{public void method(){system.out.println (" ConcreteProductA1 extends AbstractProductA "){public void method(){system.out.println (" ConcreteProductA1 extends AbstractProductA "){ ); }} Public class ConcreteProductA2 extends AbstractProductA{public void method(){system.out.println (" ConcreteProductA2 extends AbstractProductA "){public void method(){system.out.println (" ConcreteProductA2 "); ); }} Public class ConcreteProductB1 extends AbstractProductB{public void method(){system.out.println (" ConcreteProductB1 "){public void method(){system.out.println (" ConcreteProductB1 "); ); }} Public class ConcreteProductB2 extends AbstractProductB{public void method(){system.out.println (" ConcreteProductB2 "); ); } } public abstract class AbstractFactory{ public abstract AbstractProductA createProductA(); public abstract AbstractProductB createProductB(); } public class ConcreteFactory1 extends AbstractFactory{ public AbstractProductA createProductA(){ return new ConcreteProductA1(); } public AbstractProductB createProductB(){ return new ConcreteProductB1(); } } public class ConcreteFactory2 extends AbstractFactory{ public AbstractProductA createProductA(){ return new ConcreteProductA2(); } public AbstractProductB createProductB(){ return new ConcreteProductB2(); }}Copy the code

In fact, Android source code for abstract factory appears relatively few, fortunately, abstract factory method is not complicated, easy to remember, we can understand from the Service, Service onBind method can be regarded as a factory method, From a framework perspective, a Service can be viewed as a concrete factory, which is an early form of the abstract factory method pattern.

 public class BaseService extends Service{
    @Nullable
    @Override
    public IBinder onBind(Intent intent){
        return new Binder();
    }

}Copy the code

6 Policy Mode

Definition: There are a series of algorithms, each algorithm is encapsulated (each algorithm can be encapsulated into a different class), each algorithm can be replaced with each other, and the policy pattern allows the algorithm to change independently of the customers that use it.

To understand this, for example, you now have many sorting algorithms: bubble, hill, merge, select, and so on. A common way to choose which algorithm to use depends on the actual situation is to use if… The else or case… And other conditional judgment statements to select. However, this class can become expensive to maintain and prone to errors.

How to use the policy pattern, I’m not going to write the example code, but to describe it briefly, I’ll describe the algorithm selection I mentioned earlier. We can define an algorithmic abstract class AbstractAlgorithm, which defines an abstract method, sort(). Each specific sorting algorithm inherits the AbstractAlgorithm class and rewrite sort() to implement sorting. Add a setAlgorithm(AbstractAlgorithm al) to the Client class that requires sorting; Method sets the algorithm in and calls al.sort() every time the Client needs to sort.

I don’t know if a brief description will make sense to you

Take a look at where the strategy pattern appears in Android, including when using the time interpolator in property animation. When using the animation, you can choose linear interpolation LinearInterpolator, acceleration deceleration interpolation AccelerateDecelerateInterpolator, deceleration interpolator DecelerateInterpolator interpolator and custom. These interpolators are used to calculate the percentage change in the current attribute value based on the percentage time elapsed. By selecting different interpolators as required, different animation effects can be achieved. These are easier to understand, not to paste Android source code.

7 Status Mode

In the state model, behavior is determined by the state, and there are different behaviors in different states. The structure of state mode and policy mode is almost the same, mainly because the purpose and essence of their expression are different. The behavior of the state pattern is parallel and non-replaceable, while the behavior of the policy pattern is independent and interchangeable. For example, TV has two states, one is on and the other is off. When it is on, it can switch channels, and when it is off, it does not make any response when it switches channels.

public interface TvState{ public void nextChannerl(); public void prevChannerl(); public void turnUp(); public void turnDown(); } public class PowerOffState implements TvState{ public void nextChannel(){} public void prevChannel(){} public void turnUp(){} public void turnDown(){} } public class PowerOnState implements TvState{ public void nextChannel(){ System.out.println(" next channel "); } public void prevChannel(){system.out.println (" prevChannel "); } public void turnUp(){system.out.println (" turnUp "); } public void turnDown(){system.out.println (" turnDown "); } } public interface PowerController{ public void powerOn(); public void powerOff(); } public class TvController implements PowerController{ TvState mTvState; public void setTvState(TvStete tvState){ mTvState=tvState; } public void powerOn(){ setTvState(new PowerOnState()); System.out.println(" boot "); } public void powerOff(){ setTvState(new PowerOffState()); System.out.println(" shutdown "); } public void nextChannel(){ mTvState.nextChannel(); } public void prevChannel(){ mTvState.prevChannel(); } public void turnUp(){ mTvState.turnUp(); } public void turnDown(){ mTvState.turnDown(); } } public class Client{ public static void main(String[] args){ TvController tvController=new TvController(); tvController.powerOn(); tvController.nextChannel(); tvController.turnUp(); tvController.powerOff(); tvController.turnUp(); }}Copy the code

Where is the state pattern useful in Android source code? In fact, a lot of places to use, take a local example, is WIFI management module. When WIFI is on, it automatically scans the surrounding access points and displays them in the form of a list. Empty when wifi is off. The wifi management module performs different behaviors according to different states. Because of the amount of code, I won’t bother typing it in. We just need to know roughly where and how it is used in Android.

8. Responsibility chain mode

Definition: To give multiple objects the opportunity to process a request, thereby avoiding direct coupling between the sender and receiver of the request, by connecting these objects into a chain and passing the request along the chain until an object processes it.

Believe smart you are easy to understand, basic do not need examples to explain, directly into the Android source code where to use the chain of responsibility: in The Android process click event, the parent View received the first click event, if the parent View does not process to the child View, pass down in turn ~

9 Interpreter mode

Definition: Given a language, define its syntax, and define an interpreter that parses the language.

From the definition looks abstract, in fact, very simple, very easy to understand! It’s the equivalent of customizing a file format and parsing it. It doesn’t have to be that complicated!

Androidmanifest.xml defines the attributes and subtags of such tags. Specifies the usage (syntax), which is parsed through the PackageManagerService (interpreter).

10 Command Mode

Definition: The command pattern encapsulates each request as an object, allowing the user to parameterize the client with different requests. Queue or log requests, and support undoable operations.

For example to understand: when we click on the “off” the order, the system will perform a series of operations, such as suspension of event handling, save the system configuration, the end of the application process, the kernel command to shut down the computer and so on, these commands encapsulation from different objects, and then to carry out one by one, into the queue can also provide undo operation.

So where does Android use command mode? Not much at the framework level. But it is used in the bottom layer, a typical example is in the Android event mechanism, the bottom logic of the event forwarding processing. Each keystroke event is encapsulated as a NotifyKeyArgs object. Encapsulate specific event operations with InputDispatcher.

11 Observer Mode

Definition: defines a one-to-many relationship between objects. In fact, it is 1 versus N. When “1” changes, “N” will be notified and updated.

A classic application of the Observer model is a subscription-publish system. It is easy to understand that when a message is published, it is sent to each subscriber. The wechat public account we commonly use is typical. When we pay attention to a public account, when the public account pushes news, we will go to receive the news. Of course, everyone who subscribed (followed) the public account can receive the news pushed by the public account.

So where does Android use the observer mode? The function notifyDataSetChanged() notifies each Item of the ListView that the data source has changed.

12 Memo Mode

The memo pattern defines capturing the internal state of an object without breaking the closure and storing the state outside of the object so that the object can be restored to its original saved state later.

In fact, it is equivalent to an advance backup, in case of accidents, can be restored. Like our usual use of Word software, accidentally shut down, it can help us recover. In fact, it automatically backed us up.

So where does Android use memo mode? The onSaveInstanceState and onRestoreInstanceState activities use the memo mode for saving and restoring, respectively.

13 Iterator pattern

Iterator pattern definition: Provides a way to access the elements of a container object sequentially without exposing the internal representation of the object.

If you’re familiar with Java, you know that there’s an Iterator class in Java. Essentially, it uses the Iterator pattern.

When we use SQLiteDatabase’s Query method, we return a Cursor object, which is iterated over as follows:

cursor.moveToFirst();
do{

}while(cursor.moveToNext);Copy the code

14 Template method mode

Definition: Defines the framework of an algorithm in an operation, deferring steps to subclasses so that subclasses can redefine specific steps of an algorithm without changing the structure of the algorithm.

Don’t explain too much, feel the more explained the more confused, directly take Android source code for things!

As we all know, starting an Activity is very complicated, and it would be a nightmare for a developer to invoke it every time. The good news is that most of the code for starting an Activity is different, but there are many things that developers need to customize. That is, the overall algorithm framework is the same, but some steps are deferred to subclasses, such as onCreate, onStart, and so on for the Activity. This allows subclasses to redefine specific actions without changing the whole process of starting an Activity.

15 Visitor Mode

Definition: Encapsulates operations that operate on elements of a data structure. It defines new operations that operate on elements without changing the data structure.

The visitor pattern is one of the most complex of the 23 design patterns, but it is not used very often. For the most part, we do not need the visitor pattern, only for a few specific scenarios.

The application of visitor mode in Android is actually mainly in compile-time Annotation. The core principle of compile-time Annotation relies on APT(Annotation Processing Tools). Well-known open source libraries such as ButterKnife, Dagger and Retrofit are all based on APT. The detailed use of APT is not mentioned here, I will write about APT related articles later, please look forward to ~

16. Intermediary model

Definition: The mediator pattern wraps a series of ways in which objects interact without having to explicitly call each other, allowing them to be easily coupled. When the interaction between some objects changes, it does not immediately affect the interaction between some other objects to ensure that the interaction can change independently of each other. The mediator pattern transforms many-to-many interactions into one-to-many interactions.

When to use the mediator pattern? In essence, the mediator object transforms the system from a mesh structure to a media-centric star structure.

To take a simple example, a computer consists of: CPU, memory, graphics card, IO devices. In fact, to start a computer, CPU and memory are all you need. Of course, if you need to connect the display screen, you’ll have to add graphics, if you need to store the data, that is about to IO device, but this is not the most important, they are just ordinary parts apart, one thing we need to put these parts together, into a whole, this thing is the motherboard. The motherboard plays the role of intermediary, and any communication between two modules will be coordinated by the motherboard.

So where is the mediator pattern used in Android? In Binder mechanism, intermediary mode is used. For children’s shoes not familiar with Binder, please refer to my simple, Clear and Thorough Understanding of Binder. We know that various system services will submit registration to ServiceManager when the system is started. That is, ServiceManager holds references to various system services. When we need to obtain the Service of the system, For example, ActivityManager, WindowManager, etc. (all binders), the ServiceManager queries the Binder for the specified identifier, and the ServiceManager returns a reference to Binder. And the communication between the client and the server is realized through the Binder driver, where the ServiceManager and Binder driver is the intermediary.

17 Proxy Mode

Definition: Provides a proxy for other classes to control access to this object. In fact, we usually use proxy mode is also more, in fact, relatively easy to understand, that is, when we need to access an object, we do not directly access the object, but access the proxy class of the class, the proxy class can help us perform the operation we want. The proxy pattern is relatively easy to understand, and you are familiar with it since you are reading this article.

If you look at the code generated by AIDL, it will decide whether to access across processes based on the current thread. If it does not, it will return an instance. If it does, it will return a proxy. As we mentioned in Understanding Binder, cross-process communication involves writing parameters to Parcelable objects and then executing transact functions, which is a lot of code to write. AIDL does this by generating a proxy class that automatically writes these operations for us.

18 Combination Mode

Definition: Objects are organized into a tree structure to represent a partial-whole hierarchy so that users can use single objects and combined objects consistently.

The above definition is not easy to understand, so let’s start with the combination pattern used in Android. As we know, the View structure in Android is a tree structure. Each ViewGroup contains a series of views, and the ViewGroup itself is a View. This is a very typical combination pattern in Android.

19 Adapter Mode

Definition: To transform the interface of one class into another interface that the client expects, so that two classes can work together that would otherwise not work together because of interface mismatches.

The adapter pattern is easy to understand, and we use it a lot in Android development. Typical have ListView and RecyclerView. Why does ListView need to use an adapter? Basically, the ListView only cares about its individual ItemView, not what that ItemView actually shows. Our data source holds the content to be displayed. It holds the content to be displayed for each ItemView. The adapter provides the getView method for ListView to use. Each time the ListView only needs to provide location information to the getView function, which then obtains the corresponding data from the data source based on the location information. Return different views based on the data.

20 Decoration Mode

Definition: Dynamically adding additional smarts to an object. Decorator is more flexible than subclass inheritance in terms of adding functionality. Understand decorator patterns with simple code:

public abstract class Component{ public abstract void operate(); } public class ConcreteComponent extends Component{ public void operate(){ } } public class Decorator{ private Component  component; public Decorator(Component component){ this.component=component; } public void operate(){ operateA(); component.operate(); operateB(); } public void operateA(){ } public void operateB(){ } }Copy the code

So where is decoration mode on Android? ContextImpl, ContextImpl, ContextImpl, ContextImpl, ContextImpl, ContextImpl, ContextImpl, ContextImpl We know that an Activity is a Context, but an Activity doesn’t inherit from the Context, it inherits from the ContextThremeWrapper. And ContextThremeWrapper inheritance in ContextWrapper ContextWrapper inherit Context. Having said so much, what does it have to do with decorative patterns? The main thing is to introduce the ContextWrapper class. So there’s a Context inside of ContextWrapper that refers to mContext, and there’s a ContextWrapper implementation of every method of the Context, and it calls the same method of mContext in the implementation.

21 Enjoy yuan mode

Definition: Use meta-objects to effectively support a large number of fine-grained objects.

We usually contact a lot of primitives, such as Java constant pool, thread pool and so on. The main purpose is to reuse objects.

Where do you use the premium mode on Android? Message in thread communication, message.obtain () is called every time we obtain a Message, which essentially takes a reusable Message from the Message pool and avoids creating a large number of Message objects.

22 Appearance Mode

Definition: Requires that communication between the outside and the inside of a subsystem must be through a unified object.

For example, when we start a computer, we just press the on button. We don’t need to know how the disk, memory, CPU, power supply and so on work. We just care that they help us start it up. In fact, the circuitry inside is so complicated that we have no way of knowing exactly how it works. The host provides a single interface “on key” to the user.

So where does Android use appearance mode? Still going back to Context, Android has a lot of complicated functions inside such as startActivty, sendBroadcast, bindService, etc. The internal implementation of these functions is very complicated, if you look at the source code you can feel it, but we don’t need to care what it does inside, All we care about is that it starts the Activity for us, sends a broadcast for us, binds the Activity, and so on.

23 Bridge mode

Definition: Separate the abstract parts from the implementation parts so that they change independently. Essentially, a class has two dimensions of change, and both dimensions need to be extended.

The bridge mode is used a lot in Android. For example, for a View, it has two dimensions, one is its description, Button, TextView, etc. They are the description of the View, and the other dimension is to actually draw the View onto the screen, This has to do with Display, HardwareLayer, and Canvas. These two dimensions can be regarded as the application of the bridging pattern.

24 MVC, MVP, and MVVP modes

MVC

It’s called model-view-controller, or model-view-controller. The MVC structure is shown in the figure below:

The application of MVC in Android is very classic. Our layout file such as main. XML corresponds to the View layer, local database data or data downloaded from the network corresponds to the Model layer, and Activity corresponds to the Controller layer.

MVP

MVP is a Model View Presenter, and is becoming increasingly important in Android app development.



It reduces the coupling between View and Model. Completely separate View from Model. MVP is not a standardized model, it is implemented in many ways.

MVVM

The full name is Mode View ViewModel, and its structure is as follows:



When we use ListView, we will define a ViewHolder. In RecyclerView, we must use a ViewHolder. This is mainly to improve performance, because we do not need to call findViewById every time to retrieve the View. So a ViewHolder is just a ViewModel.