preface

We have studied the Builder pattern, singleton pattern, and factory method pattern used by Retrofit framework, and we will continue to review the rest of the appearance pattern, agent pattern, and strategy pattern. Welcome to join me in learning and filling in the gaps

The appearance model

The facade pattern, also known as the facade pattern, belongs to the structural pattern. In simple terms, the external and internal must be carried out through a unified object (facade object), providing an interface, making the subsystem easier to use

implementation

When we use some paid software, we need to log in or recharge. These are completed by the third-party SDK. We only need to access the corresponding functions simply

Create a facade object

The login and membership payment interfaces in the SDK can be encapsulated for external sub-apps to call

class VideoSDK {

    fun login(a) {
        val loginManager = LoginManager()
        loginManager.login()
    }

    fun pay(money:Int) {
        val payManager = PayManager()
        payManager.pay(money)
    }

}

// Log in to the system
class LoginManager {
    fun login(a) {
        println("Open login screen")
        println("Perform login operation")
        println("Login successful")}}// Payment system
class PayManager {
    fun pay(momey: Int) {
        println("Generate order information")
        println("Choose payment method")
        println("Payment successful:" + momey + "Yuan")}}Copy the code

Apps on Android

The Android facade mode is also widely used, such as the Conext class, which encapsulates many important operations, such as startActivity(), sendBroadcast(), etc., which is a unified portal for developers to call. Context is an abstract class that defines only the abstract interface. The actual implementation is in the ContextImpl class

This way we can simply call a method to start an Activity, and the Context encapsulates the details

conclusion

advantages

  • Reduce coupling between client and subsystem
  • Through the appearance of the sub-system interface encapsulation, easier to use
  • Flexibility increased, no matter how the subsystem changes, as long as we do not impression the appearance of the object, can be modified freely, better division of the hierarchy

disadvantages

  • Adding a new subsystem would require changing the code inside the facade object, violating the open and close principle
  • It would be very complex if all the subsystem functions were implemented through a single interface

Application scenarios

  • For some obvious hierarchical divisions, such as the hospital model, that is why there are corresponding receptionists at the door of the hospital to serve
  • A subsystem can be separated from the client, so that the subsystem can also be ported to other applications, with a certain degree of independence

The proxy pattern

Similarly, this pattern simply means providing proxies for other objects to control access to that object

implementation

In general, we have the following steps to use the proxy mode

  1. Sets the abstract topic class, which is the public method used to declare the object and the proxy
  2. Create a proxyed class (delegate class) that is responsible for the execution of the specific business logic through which the principal’s methods can be invoked
  3. Create a proxy class, which is a reference to the proxied class, in which the interface methods used to execute the corresponding interface methods in the proxied class
  4. The final client class, and this is where the proxy pattern is used

It can be said that the agency mode belongs to the structural mode, and I take the daigou as an example to see its specific implementation

Start by creating an abstract topic class

To be clear, daigou generally has a purchase method. Below, I create People with a purchase method

interface People {   
    / / purchase
    fun buy(a)
}
Copy the code

Create a concrete topic class

People in the country define a specific purchase process, have a buy() method, inherit the People interface, rewrite the purchase method

class BuyerRelease(people: People) : People {
    
    override fun buy(a) {
        println("Domestic need to buy an overseas skin care products")}}Copy the code

Using proxy classes

The daigou who is far away needs to know who you are and what product is that person looking to buy

class Oversea(people: People) :People {
    private varmPeople:People? = peopleoverride fun buy(a) {
        println("Overseas purchasing personnel online.....") mPeople? .buy()// Call the proxied method directly}}Copy the code

The above implementation is actually the static proxy in the proxy mode, which as the name implies, there is also a dynamic proxy, which simply needs to be generated by reflection at run time, there is no proxy class bytecode file, the relationship between them is determined at run time

The proxy interface InvocationHandler, which is implemented by overriding the invoke() method

class DynamicProxy(  // Implement InvocationHandler interface
    // The proxied object
    private val obj: Any
) : InvocationHandler {
    // Override the invoke() method
    @Throws(Throwable::class)
    override fun invoke(proxy: Any? , method:Method, args: Array<Any? >?: Any {
        println("Overseas dynamic proxy invocation method:" + method.name)
        return method.invoke(obj, args) // Call the proxied object's method}}Copy the code

In this way, we do not need to be like static proxy, interface to add a method needs all the proxy class to implement this method, greatly increasing the complexity of the code, and dynamic proxy is not the same, do not need every method for transfer, can be flexible processing, reuse greatly enhanced

Apps on Android

The most typical example of this is the Retrofit Web request library, which is mentioned briefly here to prepare for the rest of this article

  1. Writing an API
interface xxxApi {
    @POST("app/xxxx")
    @FormUrlEncoded
    fun sendEmailCode(@Field("email") email: String?).: Observable<BaseResponse<String>>
}
Copy the code
  1. Initialize the Retrofit
var retrofit: Retrofit = Builder()
    .baseUrl("https://xxxxxx")
    .build()
Copy the code
  1. Create the current instance dynamically. Note that the create method uses dynamic proxy mode
        val service:xxxApi = retrofit.create(xxxApi::class.java)
        service.sendEmailCode(xxxx)
Copy the code

conclusion

Let’s summarize the advantages and disadvantages of the proxy model

advantages

  • Reduce coupling between modules and systems
  • Callers can be protected by controlling their access rights

disadvantages

  • The addition of proxy objects may slow down the processing of requests
  • Some proxy patterns are very complex to implement and can add complexity to the system implementation

Applicable scenario

  • When an object cannot or does not want to directly access another object, it can be accessed indirectly through a proxy object
  • If the accessed object does not want to expose all of its content, it can be brokered to remove unwanted content

The strategy pattern

The policy mode is a behavioral mode. It provides a series of algorithms and forms an algorithm group for the client to call. In this way, the client can solve different problems based on different policy modes

implementation

See here, for the strategy mode or a half-understanding, we take an example to achieve, to choose leisure time to choose entertainment as an example

Define a public interface

Here’s how we choose our leisure and entertainment

interface ChoiceStragety {
    // Entertainment
    fun chase(a) // Entertainment methods
}
Copy the code

Create a concrete policy class

Implementation of abstract policy class interface, concrete entertainment

class ShoppingStrategy : ChoiceStragety {
    override fun chase(a) {
        println("Shopping.")}}class MoviesStrategy : ChoiceStragety {
    override fun chase(a) {
        println("Watch a movie.")}}class GameStrategy : ChoiceStragety {
    override fun chase(a) {
        println("Play the game.")}}Copy the code

Creating an Environment Class

Here is the need to operate different entertainment strategy, can be used in different ways

class Context(// Define the abstract policy class
    private val chaseStragety: ChoiceStragety
) {
    fun chase(a) { // Execute policies for specific policy objects
        chaseStragety.chase()
    }

    init { // The constructor passes in the concrete policy object}}Copy the code

Apps on Android

  1. Each ListView we use needs to be equipped with Adapter, depending on the actual needs of the use of different adapters, this is the use of strategy mode
    listView = (ListView)findViewById(R.id.list_view);
    
    / / use the ArrayAdapter
    listView.setAdapter(new ArrayAdapter<String>(this,R.id.item,new String[] {"one"."two"}));
    
     / / use BaseAdapter
    listView.setAdapter(new BaseAdapter() {
        @Override
        public int getCount(a) {
            return 0;
        }

        @Override
        public Object getItem(int position) {
            return null;
        }

        @Override
        public long getItemId(int position) {
            return 0;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            return null; }});Copy the code

Here’s the ListView source code

  public class ListView extends AbsListView {// Equivalent to the environment class
        @Override
        public void setAdapter(ListAdapter adapter) {// Set the policy, i.e. Adapter
            // Other code omitted}}public interface ListAdapter extends Adapter {// Abstract policy interface
        
    }
    public abstract class BaseAdapter implements ListAdapter.SpinnerAdapter {// BaseAdapter implements the ListAdapter interface
        
    }
    public class ArrayAdapter<T> extends BaseAdapter implements Filterable.ThemedSpinnerAdapter {ArrayAdapter inherits BaseAdapter and implements ListAdapter interface
        
    }
Copy the code
  • By setting up different Adapters (that is, different policies), we can write the ListView layout that meets our needs
  1. SetInterpolator is also used to interpolate strategy patterns

conclusion

In Android development, strategy mode is also used a lot, for example, let oneself re-implement a ViewPager, with Indicator, will use strategy mode?

advantages

  • The policy pattern hierarchy defines an algorithm to move common code into a parent class to avoid duplicate code
  • Provides methods to replace inherited relationships
  • Avoid using multiple conditional statements

disadvantages

  • The client must know all the policy classes when calling, so simply put, the policy mode is only suitable for cases where the client knows all the algorithms or behaviors
  • Policy classes are designed to be shareable by saving context-dependent state to the client

Application scenarios

  • Imagine an application with many similar classes that differ only in their behavior, and you can use policy patterns to dynamically select one of those behaviors
  • There are so many behaviors in an object that if you don’t use policy patterns, you have to use multiple conditional statements