One, foreword
Structural patterns describe how classes or objects are combined together to form larger structures. Just like building blocks, complex and more powerful structures can be formed through simple combinations. The implementation of structural pattern can be divided into two types, class structural pattern and object structural pattern, where:
Class structural pattern
Care about the composition of classes, by more than one class cancombination
Into a larger system, inClass structural pattern
Generally, there are only inheritance relations and interface implementation relations.Object structured pattern
Concerned with the composition of classes and objects, throughassociated
Relationships enable you to define an instance object of another class in one class, and then call its methods through that object. According to the”Principle of composite reuse“, in the system try to use association relationship to replace inheritance relationship, so mostStructural mode
Are allObject structured pattern
.
This article introduces several common structural patterns, which are:
- Flyweight Mode
- Proxy mode
- Decorator pattern
- Adapter mode (Adapter)
- Bridge mode (Bridge)
- Facade Pattern
At the same time, in order to more easily understand the design idea of structural mode, this paper will add a concept of project phase:
- During development, it also includes the early stage of development, which is generally the period when the code is not released and can be changed at will
- The stage where development is complete, released/packaged, or no source code is available and can only be remedied
Different design patterns apply at different stages of development, which is especially important when it comes to understanding the designer’s intentions
In addition, this article is the author’s personal understanding of the structural pattern, because the concept of the structural pattern is somewhat abstract (compared to the creation pattern), everyone’s understanding is not the same, so if you find the author’s description is inaccurate or even completely wrong, please feedback here, thank you
Two, structural mode: enjoy yuan mode
1. Schema definition
The Flyweight mode (also known as Flyweight mode) is an implementation of object pool. Its English name is Flyweight, which stands for lightweight. The share mode is used to reduce the memory usage as much as possible. It is suitable for scenarios where there may be a large number of duplicate objects to cache objects that can be shared, so as to achieve the effect of object sharing and avoid creating too many objects. In this way, performance can be improved.
The concept of the share pattern is relatively simple. One controversial point about the share pattern is whether the share pattern is just an implementation of object pooling, and if so, what does it mean to care about the internal and external states of objects?
In other words, is there a direct equivalence between the share model and pooling technology?
To explore this question, let’s take a look at the design Patterns book’s definition of meta-patterns:
A flyweight is a shared object that can be used in multiple contexts simultaneously. The flyweight acts as an Independent object in each context — it’s indistinguishable from an instance of the object that’s not shared. Flyweights cannot make assumptions about the context in which they operate. The key concept here is the distinction between intrinsic and extrinsic state. Intrinsic state is stored in the flyweight; it consists of information that’s independent of the flyweight’s context, thereby making it sharable. Extrinsic state depends on and varies with the flyweight’s context and therefore can’t be shared. Client objects are responsible for passing extrinsic state to the flyweight when it needs it.
— Design Patterns: Elements of Reusable Object-oriented Software
Flyweight is a shared object that can be used in multiple contexts at the same time, and in each context flyweight can be used as a separate object — no different from instances of non-shared objects. Flyweight cannot make any assumptions about the scenario in which it is running, and the key concept here is the difference between internal and external state. The internal state is stored in the Flyweight, which contains information independent of the Flyweight scenario that allows the flyweight to be shared. The external state depends on the flyweight scenario and changes according to the scenario, so it is not shareable. The user object is responsible for passing the external state to the Flyweight if necessary.
Design Patterns: The Foundation of Reusable Object-oriented Software, China Machine Press
One of the characteristics of the share mode is that the internal state of an object is mutable, while the external state is immutable and cannot be shared. So what are the internal and external states of objects? Let’s take a look at the code examples in 2.2 and see if we can find out
2. Code examples
/* State */
public class Country {
private String countryName;// Country name
private String countryArea;// Land area
//more..
public static Country query(String country){
// Use key to query memory/database stored country objects}}/* User information class */
public class UserInfo {
public Integer age;// User age
public String nickname;/ / nickname
public Country country;/ / country
//more..
public static UserInfo obtain(a){
// Maintain an object cache pool internally}}/* Test class */
public class Test {
@org.junit.Test
public void main(a) {
UserInfo sanZ = UserInfo.obtain(18."Zhang", Country.query("China"));
UserInfo siL = UserInfo.obtain(18."Bill", Country.query("China"));
// Emigrate to Singapore for retirement
siL.country = Country.query("Singapore"); }}Copy the code
There are only two classes in the code example, the user information class and the country class. In the internal state of the user information class, there is a country property. The country class corresponding to the country property maintains a set of data internally and does not expose the set() method. When a user changes the country attribute, the country object can only be queried again by the country name. This is the meaning that the internal attribute change of the share object does not affect its external status.
To summarize, a privileged object is an object that can be shared, and in the example code for 2.2, the user information class is a privileged object. Since a share object can be shared, its internal properties (name, age, country, etc.) can be reassigned, which is called the internal state of the object; The country class is an independent organization. No matter how the country attribute in the user information class changes, it will not affect the internal data in the country class. The country class is called the external state of the metadata object class
3, source anchor point
After looking at the examples in Section 2.2, let’s go back to the Implementation of Android Message
/* Pseudocode */
public class Message {
private String val;
private Message next;
private static Message root;
private static int size = 0;
private static final int MAX_SIZE = 10;
public static Message obtain(a) {
if(root ! =null) {
// Get the list header object
Message temp = root;
root = temp.next;
temp.next = null;
size--;
return temp;
}
return new Message();
}
public String getVal(a) {
return val;
}
public void setVal(String val) {
this.val = val;
}
public void recycle(a) {
// Reclaim the object, emptying the property contents
this.val = null;
// If the cache pool is not full, save the object to the head of the list
if (size < MAX_SIZE) {
next = root;
root = this; size++; }}}Copy the code
As can be seen from the code, Message implements a reuse pool with linked lists. Back to the question in 2.1, is the design idea of the linked list reuse pool of Android Message called the share element pattern? I think so, but Message has no external state
In addition to Android Message, Java also has String constant pool, int, float and other basic types of wrapper type are also used to enjoy the meta pattern, interested friends can search for it
4, summary
To sum up, the concept of share mode is to reuse objects to save memory. Share mode is suitable for the following scenarios:
- There are a large number of similar objects in the system that can be pulled out as external objects, for example
2.2
In thecountries
object - Scenarios that require buffer pools, for example
Android Message
Object, a wrapper class for Java primitive types
Some books/materials translate the meta mode asFly quantity model
This is something to be aware of.The flyweight pattern
andFly quantity model
Is the same
The code covered in this section is here
Structural mode: agent mode
1. Schema definition
Proxy mode refers to adding new functions to the original class by adding new proxy classes without modifying the original class
There are two types of scenarios implemented by the proxy pattern, outer classes and inner classes.
External classes are generally used when the original class cannot be changed. Take method time statistics in 3.2 for example, to count the time of each Stack method, we can create StackProxy class inherited from Stack class, and then call Stack methods in StackProxy and add the code of time statistics.
An inner class is a condition in which the original class code can be changed, usually by abstracting a unified interface that is implemented by both the implementation class and the proxy class, with logical code added to the proxy class; Taking Stack time statistics as an example, we can abstract out IStack class, create Stack class to realize IStack interface to complete the function, create StackProxy class to realize IStack interface to complete the time statistics logic.
The principles and code implementation of the proxy pattern are not difficult to grasp, so let’s look at the code examples in 3.2
2. Code examples
2.1 Implementation of inner classes
/* Unified interface class */
public interface IStack {
void push(int val);
int pop(a);
}
/* Implementation class */
public class Stack implements IStack {
private Node root;
private int size = 0;
@Override
public void push(int val) {
root = new Node(val, root);
size++;
}
@Override
public int pop(a) {
if(root ! =null) {
Node temp = root;
root = root.next;
size--;
return temp.val;
}
throw new EmptyStackException();
}
private static final class Node {
int val;
Node next;
public Node(int val, Node next) {
this.val = val;
this.next = next; }}}/* Proxy class */
public class StackProxy implements IStack {
private final IStack stack;
public StackProxy(IStack stack) {
this.stack = stack;
}
@Override
public void push(int val) {
long start = System.currentTimeMillis();
stack.push(val);
System.err.println("push:" + (System.currentTimeMillis() - start));
}
@Override
public int pop(a) {
long start = System.currentTimeMillis();
int res = stack.pop();
System.err.println("pop:" + (System.currentTimeMillis() - start));
returnres; }}/* Use examples */
public class Test {
@org.junit.Test
public void main(a) {
IStack stack = new StackProxy(newStack()); }}Copy the code
The requirement is to count the time it takes to insert and pop methods in the Stack. If the Stack is the only one of these roles, then the count time needs to be coupled to the business code, violating the single responsibility principle. At this time, we can introduce the proxy mode to solve this problem, divide the Stack class into three roles (unified interface, implementation class, agent class), decouple the statistical logic from the actual business, keep the implementation class’s responsibilities single, through the implementation of abstract interface to complete the work of the agent is called the proxy mode of the internal class implementation
2.2 Implementation of external classes
/* Proxy class */
public class StackProxy<E> extends java.util.Stack<E> {
@Override
public E push(E item) {
long start = System.currentTimeMillis();
E push = super.push(item);
System.err.println("push:" + (System.currentTimeMillis() - start));
return push;
}
@Override
public synchronized E pop(a) {
long start = System.currentTimeMillis();
E pop = super.pop();
System.err.println("pop:" + (System.currentTimeMillis() - start));
returnpop; }}/* Use examples */
public class Test {
@org.junit.Test
public void main(a) {
Stack<Integer> stack = newStackProxy<>(); }}Copy the code
Following up on the requirement for time statistics above, in this example, the Stack class comes from the java.util package and the internal code cannot be changed. The only way to do this is to create StackProxy that inherits the Java.util.Stack class and add time statistics to each method to fulfill the requirements, which is called the external class implementation of the proxy pattern
Dynamic proxy
As we found in sections 2.1 and 2.2, the logic for time statistics is similar in each method, and based on the development principle of being automatic and never manual, we can solve this problem by using dynamic proxies, which are often used in actual development. The so-called Dynamic Proxy means that we do not write a Proxy class for each original class in advance, but dynamically create the corresponding Proxy class of the original class when running, and then replace the original class with the Proxy class in the system.
Implementing dynamic proxies is a simple matter if you use the Java language, because the Java language already provides the syntax for dynamic proxies. Let’s take a look at how Java’s dynamic proxy implements the functionality of the previous section:
/* Dynamic proxy class */
public class StackDynamicProxy {
public Object createProxy(Object proxyObject) {
Class[] interfaces = proxyObject.getClass().getInterfaces();
DynamicProxyHandler handler = new DynamicProxyHandler(proxyObject);
return Proxy.newProxyInstance(proxyObject.getClass().getClassLoader(), interfaces, handler);
}
private static class DynamicProxyHandler implements InvocationHandler {
private final Object proxyObject;
public DynamicProxyHandler(Object proxyObject) {
this.proxyObject = proxyObject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long start = System.currentTimeMillis();
Object result = method.invoke(proxyObject, args);
System.err.println(method.getName() + ":" + (System.currentTimeMillis() - start));
returnresult; }}}/* Use examples */
public class Test {
@org.junit.Test
public void main(a) {
StackDynamicProxy proxy = new StackDynamicProxy();
IStack stack = (IStack) proxy.createProxy(newStack()); }}Copy the code
4, source anchor point
Proxy mode in the application of Android source code, in addition to the classic Retrofit, Android Hook, plug-in also use proxy mode, the author here is a brief introduction to plug-in is how to use proxy mode to replace Activity:
The Instrumentation class is ultimately responsible for creating the Activity object when the context.startActivity() method is called to start the Activity. So, we can create a proxy class to replace the system Instrumentation object, in the monitoring to start the placeholder Activity in the AndroidManifest, replace the target Activity in the plug-in, the general process is as follows:
- create
Instrumentation
The proxy classInstrumentationProxy
public class InstrumentationProxy extends Instrumentation {
private final Instrumentation instrumentation;
public InstrumentationProxy(Instrumentation instrumentation) {
this.instrumentation = instrumentation; }}Copy the code
- Hook system
Instrumentation
//1. Obtain the ActivityThread object in the processClass<? > classes = Class.forName("android.app.ActivityThread");
Method activityThread = classes.getDeclaredMethod("currentActivityThread");
activityThread.setAccessible(true);
Object currentThread = activityThread.invoke(null);
Field instrumentationField = classes.getDeclaredField("mInstrumentation");
instrumentationField.setAccessible(true);
Instrumentation instrumentationInfo = (Instrumentation) instrumentationField.get(currentThread);
//2. Create the proxy object and save the mInstrumentation instance to the proxy object
InstrumentationProxy proxy = new InstrumentationProxy(instrumentationInfo);
//3. Replace the system mInstrumentation example with a proxy object
instrumentationField.set(currentThread, proxy);
Copy the code
- Overridden in the proxy class
execStartActivity
methods
public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options) {
/ /...
ComponentName componentName = intent.getComponent();
String packageName = componentName.getPackageName();
String classname = componentName.getClassName();
if (classname.equals("TargetActivity")) { // Determine if it is the target Activity
intent.setClassName(who, ProxyActivity.class.getCanonicalName()); // The Activity starts instead of a placeholder
}
/ /...
}
Copy the code
- Overridden in the proxy class
newActivity
Method to create the actually startedActivity
public Activity newActivity(ClassLoader cl, String className, Intent intent) {
/ /...
String classnameIntent = intent.getStringExtra(ACTIVITY_RAW);
String packageName = intent.getComponent().getPackageName(); // Get the package name and class name of the actual Activity stored in the Intent
if (className.equals(ProxyActivity.class.getCanonicalName())) {
ComponentName componentName = new ComponentName(packageName, classnameIntent); // Replace the package name and class name of the real Activity
intent.setComponent(componentName);
className = classnameIntent;
}
/ /...
}
Copy the code
Hook Instrumentation to implement Activity plug-in start summary:
- Hook system
Instrumentation
Object set to createThe proxy class
- Modify startup in the proxy class
Activity
theIntent
, will start the targetActivity
Replace withPlaceholder Activity
So as to avoid the check of registration list - Override in the proxy class
newActivity()
Change the initiated activity back to the real target, and then continue with the original logic
AIDL cross-process communication provided by Android also uses proxy mode. The interface object saved by asInterface() on the Client side is actually the proxy on the Server side. Here is a small Demo implemented by the author, interested students can click to check
5, summary
Finally, let’s review the definition of the proxy pattern: to add new functionality to the original class by adding a new proxy class without modifying the original class
Implementations are divided into inner classes, which use interfaces or abstract classes, and outer classes, which use inherited implementations
The proxy pattern is often used in the development of business systems to develop non-functional requirements such as monitoring, statistics, and logging. We decoupled these additional functions from business functions and put them in a proxy class that lets developers focus only on the business side of development. In addition, the proxy pattern is also used in cross-process communication, plug-in, and other scenarios
The code covered in this section is here
Four, structural mode: decorator mode
1. Schema definition
In terms of code structure, the decorator pattern and the proxy pattern (inner class implementation) are very similar. In terms of structure, they are not unrelated, but identical. Recall from the previous section that the proxy pattern is defined as adding new functionality to the original class by adding a new proxy class without changing the original class
This phrase is decoration mode: decoration mode is to enhance the properties of the original class by adding new decoration classes without changing the original class.
Although decorated and proxy patterns are very similar in structure, they are very different in application scenarios; Decoration pattern mainly solves the problem that inheritance is too complicated in daily development, and replaces inheritance by combination, that is to say, decoration pattern is one of the alternatives of inheritance relationship
There are generally two ways to add behavior to a class or object:
- Inheritance: Inheriting an existing class allows a subclass to have its own methods as well as the parent class’s methods, which is equivalent to adding behavior to the parent class
- Association: An object of one class is embedded in another object, and the other object decides whether to invoke the behavior of the embedded object to extend its own behavior
Let’s explain why decorator is an alternative to inheritance through the application scenario simulated by 4.2 sample code:
2. Code examples
/* Clothes - interface */
public interface IClothes {
int getWarmValue(a);
}
/* Clothes - coat */
public class Coat implements IClothes {
private final IClothes clothes;
public Coat(IClothes clothes) {
this.clothes = clothes;
}
@Override
public int getWarmValue(a) {
return clothes.getWarmValue() + 50; }}/* Clothes-pants */
public class Pants implements IClothes {
private final IClothes clothes;
public Pants(IClothes clothes) {
this.clothes = clothes;
}
@Override
public int getWarmValue(a) {
return clothes.getWarmValue() + 50; }}/* Clothes-shirt */
public class Shirt implements IClothes {
private final IClothes clothes;
public Shirt(IClothes clothes) {
this.clothes = clothes;
}
@Override
public int getWarmValue(a) {
return clothes.getWarmValue() + 30; }}/* Use examples */
public class Test {
@Test
public void main(a) {
IClothes bob = new Bob();
// Take a bath in the bathroom
System.out.println("Warmth value with nothing on:" + bob.getWarmValue());
bob = new Shirt(bob);
// Get dressed at home
System.out.println("Warmth value with a shirt on:" + bob.getWarmValue());
bob = new Pants(bob);
System.out.println("Warmth value with another pair of pants on:" + bob.getWarmValue());
// Go out to meet friends
bob = new Coat(bob);
System.out.println("Warmth value with another coat on:" + bob.getWarmValue());
}
private class Bob implements IClothes {
@Override
public int getWarmValue(a) {
return 0; }}}Copy the code
Print the result
Warmth value with nothing on:0Warmth value with a shirt on:30Warmth value with a pair of pants on:80Warmth value with another coat on:130
Copy the code
In this example, the IClothes interface is implemented for shirts, pants, coats, etc., and the warmth degree of different clothes is different, that is, the enhanced attribute value of each clothing is different. The collocation of clothes in different scenes is also different. If inheritance is used instead of decoration mode in this example, various permutations and combinations may escape explosion. With decorator mode, you only need to generate one decorator class for each item of clothing, so decorator mode is more flexible than subclass implementation in terms of adding object functionality.
3, source anchor point
In Geek Time: The Beauty of Design Patterns, Mr. Wang zheng mentioned the use of decoration patterns in the design of Java I/O classes. Unfortunately, the author is not good enough to reexpress Mr. Wang’s ideas in his own language. I usually read/write files by the tool class encapsulated in the project to operate, I really do not know how to design Java I/O, about the use of Java I/O class and which design mode to use the author will write a separate article to introduce, interested students can search other materials to read
In addition to Java I/O, many articles refer to the Android Context as a decorator pattern, but I have a different opinion on this point
Photo credit: Drawn by myself
As can be seen from the class diagram, Application, Service, and Activity all inherit from ContextWrapper; ContextWrapper and ContextImpl are both Context implementation classes, but in ContextWrapper, all methods are delegated to mBase(ContextImpl). Therefore, based on the current structure of Context, the author thinks that Context is more appropriate to say proxy mode
However, let’s change the scenario a little bit. Suppose we now add a new ContextImpl2 role to make the permissions of the Application and the Activity different and more powerful, so that it is more consistent with the decorator Settings
Photo credit: Drawn by myself
4, summary
Decorator patterns are more flexible than inheritance to implement extensions. Decorator and proxy patterns are very similar to each other, but they apply to different scenarios. When looking at similar code structures, context is needed to determine the designer’s intent; In addition, decorative patterns and proxy patterns can be used at different stages of a project. Proxy patterns can be used at any stage, while decorative patterns should usually be considered at the early design stage of a project.
The code covered in this section is here
Five, structural mode: adapter mode
1. Schema definition
The adapter pattern is defined to transform incompatible interfaces into compatible interfaces so that classes that would otherwise not work together because of incompatible interfaces can work together
There are two implementations of the adapter pattern: class adapter and object adapter; Class adapters are implemented using inheritance relationships and object adapters are implemented using composition relationships, and the differences between the two can be seen here
In real development, the adapter pattern often acts as an implementation converter for legacy issues, often in situations where code changes are costly late in the project, or where a function relies on a third party to implement it, for example:
Assuming that we have integrated Alipay SDK in an Android project, the location information provided by Autonavi is needed to call the login method. However, Tencent Map has been connected to the earlier project, and Tencent Map can provide the location information required by Alipay, but the entry type is different and the interface is incompatible. In this scenario, we can use the Adapter mode to define a packaging class to convert the location information provided by Tencent Map into the type required by Ali Pay. This packaging class refers to the Adapter.
2. Code examples
/* Alipay SDK*/
public class AliPay {
/* The login method requires passing in location information */
public boolean login(String id, String pwd, IAMap.AMapParams location) {
return res;
}
/* Amap interface */
public interface IAMap {
AMapParams getAMapParams(a);
class AMapParams {
public float aMapLongitude;/ / longitude
public float aMapLatitude;/ / latitude}}}/* Tencent Map SDK*/
public class TencentMap {
private final TencentMapParams params;
public TencentMap(a) {
params = new TencentMapParams();
params.tencentMapLongitude = new Random().nextFloat();
params.tencentMapLatitude = new Random().nextFloat();
}
/* Provide Tencent map location information */
public TencentMapParams getTencentMapParams(a) {
return params;
}
public static class TencentMapParams {
public float tencentMapLongitude;/ / longitude
public float tencentMapLatitude;/ / latitude}}/* Adapter, which uses inheritance implementation, can also use object implementation instead */
public class Adapter extends TencentMap implements IAMap {
@Override
public AMapParams getAMapParams(a) {
// Convert the location information provided by Tencent Map to autonavi's location information
AMapParams aMapParams = new AMapParams();
TencentMapParams tencentMapParams = this.getTencentMapParams();
aMapParams.aMapLongitude = tencentMapParams.tencentMapLongitude;
aMapParams.aMapLatitude = tencentMapParams.tencentMapLatitude;
returnaMapParams; }}/* Use examples */
public class Test {
@Test
public void main(a) {
Adapter adapter = new Adapter();
AliPay aliPay = new AliPay();
aliPay.login("admin"."admin", adapter.getAMapParams()); }}Copy the code
There are three roles in the code example, Ali Pay SDK, Tencent Map SDK and Adapter. The role of the Adapter is to convert the location information provided by Tencent Map into the location information of the Autonavi interface that Ali Pay wants to be based on, which is the so-called incompatible interface into compatible interface
3, source anchor point
In the Android field, most of the blogs always take RecyclerView.Adapter as an example to explain the Adapter mode, which the author thinks may not be very appropriate, after viewing part of RecyclerView source code and explain the design mode of books, The author thinks that although the Adapter of RecyclerView is called Adapter, the work it completes is that the bridge mode may be more suitable for some
The source code sample of the adapter pattern is not found by the author, if you find the source code application of the adapter pattern, please tell me here, thank you
4, summary
To summarize, the adapter pattern can be understood simply as a converter, mostly as a compensation mechanism to remedy design flaws or when, as in the 5.2 code example, the source code cannot be changed; Using this mode is a “no choice”, if we can avoid interface incompatibilities at the beginning of the design, then this mode has no chance of application
The code covered in this section is here
Structural mode: bridge mode
1. Schema definition
The definition of the bridge pattern is simple: separate the abstract part from its implementation part so that both can vary independently.
Due to the short definition of the bridge mode, there is a lot of controversy about the bridge mode online, whether in Chinese or English sites; At issue is whether the bridging pattern is defined by GoF to separate implementation from abstraction, or whether two (or more) dimensions of a class vary independently and can be combined so that these two (or more) dimensions can be extended independently; If the latter, what distinguishes it from the strategic pattern
At present, there is no agreement on the bridging mode, so this article is based on the original definition of GoF. I personally equate the bridge pattern with the implementation of the dependency inversion principle, including the bridge pattern mentioned above and the code examples that follow, so you can skip this section if you don’t understand it
2. Code examples
public interface IImageLoader {
void loadUrlIntoImageView(ImageView view, String url);
}
public class ImageLoader implements IImageLoader {
@Override
public void loadUrlIntoImageView(ImageView view, String url) {
//do something..}}Copy the code
The above example is relatively simple, but most implementations of the bridge pattern extend it to add more classes and more methods
3, summary
The bridge pattern is often used in actual development. Most Android projects use the bridge pattern to isolate third-party libraries. Take the image loading framework as an example, where the abstraction layer that defines attribute behavior is placed in the Base module and the implementation layer is usually placed in the Business or APP layer
Bridge Pattern, Bridge Pattern 2, Bridge Pattern, Bridge Design Pattern in Java
Vii. Structural mode: appearance mode
1. Schema definition
Appearance model is to point to to a complex system to provide a uniform appearance (interface), convenient for the caller to use, will not change any interface Goods order, for example, when the server receives the order with the client’s request, need to check the user’s identity, the information such as inventory, price, postage, coupons, appearance model largely improve the client use convenience, The client does not need to care about the details of subsystem work, through the appearance of the role can call related functions
From the point of view of their function, I think it is more appropriate to call them encapsulation patterns, because they also seem to solve the problem of exposing method properties to the outside world and cannot even be called design patterns
Eight, summary
This article introduces six of the seven structural patterns, of which four design patterns — broker, decorator, adapter, and bridge — have very similar code structures, except for the relatively independent meta-pattern and facade pattern. Broadly speaking, they can all be referred to as Wrapper patterns, where the original class is rewrapped with the Wrapper class.
Although the code structure is similar, the intent of the four design patterns is very different, that is, the problem to be solved, the application scenario, and the appropriate project phase, which are the main differences between them
- Proxy mode: The proxy mode defines a proxy class for the original class without changing the interface of the original class. The primary purpose of the proxy mode is to control access, rather than enhance functionality, which is the biggest difference from the decorator mode.
- Decorator pattern: The Decorator pattern also enhances the functionality of the original class without changing the interface of the original class, and supports nested use of multiple decorators.
- Adapter pattern: The adapter pattern is an afterthought strategy. The adapter provides a different interface from the original class, whereas the proxy and decorator patterns provide the same interface as the original class.
- Bridge pattern: The purpose of the bridge pattern is to separate the interface part from the implementation part so that they can be changed relatively easily and independently.
Conclusions:Geek Time: The Beauty of Design Patterns – King Of Contention
Stack Overflow has a discussion about the different modes of proxy, adaptation, adapter, and bridge. Click on the link below to check out the discussion
Stackoverflow.com/questions/3…
Composite patterns are not included in this article, but you can learn more about them here
The full text after
Again: the above is the author’s personal rightStructural mode
As a result ofStructural mode
The concept of is somewhat abstract compared with that ofCreation pattern
). If you find any inaccuracies or even outright errors in my description, please go tohereGive feedback. Thank you
Ix. Reference materials
- Graphic design patterns
- refactoringguru.cn
- Geek Time: The Beauty of Design Patterns – King Of Contention
- Design Patterns: The Foundation of Reusable Object-oriented Software
- “Android source code design mode analysis and combat” – He Honghui/Aixinmin
- Design Patterns in Plain English -LeetCode
- Head First Design Patterns
- Android plug-in – Hook technology necessary for master