Common Android design patterns

Due to the frequency of project changes, as a programmer, we need to master the necessity of design patterns. It goes without saying ~ ~. The following is a summary of some design patterns I have learned. Next, we will mainly explain several common modes, mainly the following:

  • Observer mode
  • Adapter mode
  • proxy pattern
  • Factory mode
  • Singleton mode
  • Command mode

1. Observer Pattern

interpretation:

Observer mode defines a one to many dependency, which allows multiple observer objects to listen to a topic object at the same time. When the status of the topic object changes, it will notify all observer objects so that they can update themselves automatically.

Story understanding:

Observers want to know the situation of all mm in the company, so long as they join the MM information e-mail group of the company. tom is responsible for collecting information. When new information is found, we don't need to notify us one by one, but directly publish it to the e-mail group. As subscribers (observers), we can receive information in time.

Common examples:

  1. BaseAdapter.registerDataSetObserver and BaseAdapter.unregisterDataSetObserver are used to register and unregister a DataSetObserver with basedater;
  2. Use ContentObserver to listen for database changes.

Applicable scenarios:

  1. When changing one object requires changing other objects at the same time, we don't know how many objects need to be changed;
  2. When an object must notify other objects, it cannot assume who the other objects are

Observer mode mainly includes two objects: observer and observed. In this mode, Observable represents the observed. This object is an abstract class and can only be inherited. Observer represents an observer. It is an interface, so there can be multiple observers. The classes that implement the interface belong to the observer. This is a vivid and detailed demo on the Internet: Observed:

public class MyPerson extends Observable {

    private int age;
    private String name;
    private String sax;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
        setChanged();
        notifyObservers();
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
        setChanged();
        notifyObservers();
    }

    public String getSax() {
        return sax;
    }

    public void setSax(String sax) {
        this.sax = sax;
    }

    @Override public String toString() {
        return "MyPerson [age=" + age + ", name=" + name + ", sax=" + sax + "]";
    }
}

MyPerson is the two way in which the setChange and notifyObservers are called by the observers. The former is to inform the data changes, and the latter is to send the signals to the observers.

Observer:

public class MyObserver implements Observer {

    private int i;
    private MyPerson myPerson; //Observed object
    public MyObserver(int i) {
        System.out.println("I'm an observer---->" + i);
        this.i = i;
    }

    public int getI() {
        return i;
    }

    public void setI(int i) {
        this.i = i;
    }

    public MyPerson getMyPerson() {
        return myPerson;
    }

    public void setMyPerson(MyPerson myPerson) {
        this.myPerson = myPerson;
    }

    @Override public void update(Observable observable, Object data) {
        System.out.println("Observer---->" + i + "Get updated!");
        this.myPerson = (MyPerson) observable;
        System.out.println(((MyPerson) observable).toString());
    }

}

The Observer needs to implement the Observer interface, in which there is only one update method. When the Observer receives the notification signal (observed), it will execute this action.

2. Adapter Pattern

interpretation:

The interface of a class is transformed into another interface expected by the client, so that the two classes that cannot work together due to interface mismatch can work together. The adaptation class can return an appropriate instance to the client according to the parameters.

Story understanding:

At a friend's party, I met a beautiful Sarah from Hong Kong, but I can't speak Cantonese. She can't speak Mandarin, so I had to turn to my friend kent. As the Adapter between me and Sarah, he allowed me and Sarah to talk to each other (I don't know if he will play with me).

Common examples:

ListView is used to display list data, but there are many forms as list data sets, including Array and Cursor. We need the corresponding adapter as a bridge to process the corresponding data (and form the view required by ListView).

Applicable scenarios:

  1. The business interface is incompatible with the working class (for example, some methods to implement the interface are missing in the class), but they need to work together;
  2. Provide interfaces for new business requirements based on existing interfaces and classes.

Adapter patterns are divided into class adapter patterns and object adapter patterns. With regard to the class adaptation mode, because of the single inheritance of java, when a class has been inherited, the other can only be the interface, and the corresponding methods need to be implemented manually. In this way, any subclass that meets the requirements can be created on the client to realize specific functions. The other object adapter is not implemented by inheritance, but by direct association, or delegation. For details, see this blog Adapter mode: class adapter, object adapter

Next, let's explain with ListView and ArrayAdapter ListAdapter:

public interface ListAdapter {
    public int getCount();
    Object getItem(int position);
    long getItemId(int position);
    View getView(int position, View convertView, ViewGroup parent);
    boolean isEmpty();
}

As a client, the required target interface of ListView is ListAdapter, which includes getCount(),getItem(),getView(). In order to be compatible with the data source of list < T > data type, ArrayAdapter adapter is specially defined. In short, it is to modify the data source for the target interface. The abstract class BaseAdapter omits other codes. Only two methods are listed here:

public abstract class BaseAdapter implements ListAdapter,SpinnerAdapter {
    // ... ...
    public View getDropDownView(int position, View convertView, ViewGroup parent) {
        return getView(position, convertView, parent);
    }
    public boolean isEmpty() {
        return getCount() == 0;
    }
}

ArrayAdapter encapsulates list < T > into the implementation of ListAdapter to meet the call of ListView:

public class ArrayAdapter < T > extends BaseAdapter implements Filterable {
    private List < T > mObjects;
    //I'll just list this constructor. You know what that means
    public ArrayAdapter(Context context, int textViewResourceId, T[] objects) {
        init(context, textViewResourceId, 0, Arrays.asList(objects));
    }

    private void init(Context context, int resource, int textViewResourceId, List < T > objects) {
        mContext = context;
        mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        mResource = mDropDownResource = resource;
        mObjects = objects; //The reference object also expresses the meaning that combination is superior to inheritance
        mFieldId = textViewResourceId;
    }
    public int getCount() {
        return mObjects.size();
    }

    public T getItem(int position) {
        return mObjects.get(position);
    }

    public View getView(int position, View convertView, ViewGroup parent) {
        return createViewFromResource(position, convertView, parent, mResource);
    }
    // ... ...
}

We successfully passed list < T > as the data source to ListView in the form of the desired target interface. This is actually a kind of object adapter.

3. Proxy Pattern

interpretation:

By introducing a new object to operate on the real object or taking the new object as a substitute for the real object, the implementation mechanism is proxy mode (providing a proxy for other objects to control access to this object)

Story understanding:

Campus agent acts as an agent for his corresponding boss, and the job of this campus agent is to visit students on campus, such as questionnaires to students. Students are other objects in the official statement. The boss of the campus agent controls the access to students by controlling the campus agent.

Common examples:

The ActivityManagerProxy class is a Proxy, which is the Proxy of ActivityManagerNative. That is to say, ActivityManagerProxy is the Proxy class, and ActivityManagerNative is equivalent to the "supervisor role" "Class. They all have a common interface iaactivitymanager. ActivityManager is equivalent to the client of Proxy mode. In this class, you can see a large number of getxxx functions, which will call getDefault() of ActivityManagerNative class Method, which obtains a common singleton IActivityManager reference, and then calls the implementation in the Proxy through polymorphism

Applicable scenarios:

There are several applications of agent mode: remote agent, virtual agent, security agent, etc Making wedding clothes for others -- agency model Please take a look at the following structural diagram (a detailed and vivid example seen on the Internet):

Subject class: defines the common interface between RealSubject and Proxy, so that Proxy can be used wherever RealSubject is used. RealSubject class: defines the real entity represented by the Proxy. Proxy class: save a reference so that the proxy can access the entity and provide the same interface as the interface of the Subject, so that the proxy can be used to replace the entity. Next, let's implement the mode:

1.Subject class: Image.java

/**
 * Subject class
 */
public abstract class Image {

    public abstract void displayImage();

}

2.RealSubject class: RealImage.java

import com.andyidea.patterns.subject.Image;

/**  
 * RealSubject class  
 */
public class RealImage extends Image {
    private String filename;
    public RealImage(String filename) {
        this.filename = filename;
        loadImageFromDisk();
    }

    private void loadImageFromDisk() {

        System.out.println("Loading   " + filename);
    }

    @Override public void displayImage() {

        System.out.println("Displaying " + filename);
    }

}

3.proxy class: ProxyImage.java

import com.andyidea.patterns.realsubject.RealImage;
import com.andyidea.patterns.subject.Image;

/**
 * Proxy class
 */
public class ProxyImage extends Image {
    private String filename;
    private Image image;

    public ProxyImage(String filename) {
        this.filename = filename;
    }

    @Override public void displayImage() {

        if (image == null) {
            image = new RealImage(filename);
        }
        image.displayImage();
    }

}

4. Client test class: ProxyClient.java

import com.andyidea.patterns.proxy.ProxyImage;
import com.andyidea.patterns.subject.Image;

/**
 * Proxy mode client test class
 */
public class ProxyClient {

    public static void main(String[] args) {
        System.out.println("Welcome to my Blog!" + "\n" + "Proxy Patterns." + "\n" + "-------------------------------");

        Image mImage1 = new ProxyImage("My.Image1");
        Image mImage2 = new ProxyImage("My.Image2");

        mImage1.displayImage();
        mImage2.displayImage();
    }
}

The operation results are as follows:

Welcome to my Blog! 
Proxy Patterns 
-------------------------------  
Loading My.Image1  
Displaying My.Image1  
Loading My.Image2  
Displaying My.Image2

To sum up, a proxy class saves a reference to an entity and implements the same interface method as the entity. In this way, it can replace the entity!!

The above is the understanding of observer mode, adapter mode and agent mode

Posted on Mon, 22 Nov 2021 15:06:48 -0500 by DaiWelsh