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
- Sets the abstract topic class, which is the public method used to declare the object and the proxy
- 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
- 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
- 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
- Writing an API
interface xxxApi {
@POST("app/xxxx")
@FormUrlEncoded
fun sendEmailCode(@Field("email") email: String?).: Observable<BaseResponse<String>>
}
Copy the code
- Initialize the Retrofit
var retrofit: Retrofit = Builder()
.baseUrl("https://xxxxxx")
.build()
Copy the code
- 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
- 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
- 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