1. Introduction
I won’t go into the general definition of design patterns. I will just briefly talk about the design patterns I understand. The main purpose of the design patterns I understand is to make use of object-oriented (classes, interfaces, etc.) features to make the code easier to extend, easy to reuse, easy to maintain. These three characteristics also require us not to accumulate too many functions into one class, but distribute to more classes. Therefore, twenty or more design patterns are mainly designed around the above four purposes.
The book PHP Design Patterns talks about 19 design patterns, but in fact most of the design patterns have the same thinking and form in terms of ideology or design. I will classify and summarize them below so that everyone can learn more about them. It is good to understand this book, but it is best for everyone to read this book. The usage examples in it are relatively simple. When reading, remember this book to make the code simpler. There are some places that should be more standardized by implementing interfaces. Add interface.
(Note: Since this article is a summary of the book "php Design Patterns", I have mentioned the examples in the book but not written them in this article due to time constraints. You can view the e-book , I will also add examples in articles introducing each mode separately or in this article in the future)
2. Patterns to consider when creating classes
The final concept of object-oriented is class. Class is an important step in converting from process-oriented to object-oriented. Then when creating a class, how to realize the dependencies between classes is a very important issue. The following patterns are aimed at this issue.
1. Builder Mode
We should try to reduce the appearance of new in the code. This is an important way to create a class, but we should try to make it appear in the builder or factory, rather than in the method of a class. . The first reason is that the initialization method of this class may be more troublesome. It not only requires new, but also needs to pass parameters into its new constructor. Then we must first establish those parameters, and there may be objects in those parameters that need new. This initialization operation It is extremely long; the second reason is that it is very likely that the requirements of this class may change in the future, so we need to change the initialization operation, and the change operation is also performed in other classes, which does not comply with the principle of independence between classes.
2. Factory mode-extended builder mode
When the factory pattern is mentioned in many codes and frameworks, what it actually does is the builder pattern. I think the meaning of the factory pattern is more of an abstract factory that makes the builder pattern more flexible. Following the concept of the builder pattern, if there are some classes that have a standard creation process, then we can first build an abstract project, and then each concrete class inherits this class. The pizza factory is a good example.
3. Supplement: The concept of service-the core of many PHP frameworks and the implementation of dependency injection. Dependency injection is more important, I will explain it in other articles.
If we look at the two major frameworks of PHP, symfony and zend framework, we will find that there is a very important concept called dependency injection. That is, if you solve the problem of dependency between classes, the implementation method is very important. The concept is called service, or service container. In my understanding, this is very similar to the factory pattern. In ZF, you can also point a service to a specific factory, and in the factory class, we can also implement abstract factories, so the two are conceptually similar, but they are not the same. A non-conflicting way. It will be introduced separately later.
3. When needs change or functions are added
The following patterns can make it easier for us to reuse code
1. Adapter mode
We say that when the function changes, we should ensure that the interface of the class remains unchanged. This can ensure that when a class changes, the code for using it or using its class does not need to change. However, after all, there will be codes and classes that violate this principle. For example, in the example given in the book, the function of decomposing ErrorObject should be implemented by the logtocsvadapter class when the requirements change. However, there may be many reasons (such as the code cannot be changed, Not open source), did not do this. The adapter pattern is used to handle this situation. It can reimplement an interface that meets the requirements by extending (such as the usage in the book) or by using it as a member variable.
2. Decorator mode
Form: Use the decorated class as its member and call the method through the member.
You can use this pattern when you want to add functionality to a class but are afraid of changing it, but this idea cannot fundamentally solve the problem.
Another common scenario is if you only want to show others some functions of this class but not all functions.
3. Mediator mode (similar to event mode)
Form: Multiple related classes have the mediator class as their member. Calling a certain method will change the status of all classes registered in the mediator through the mediator, so the registered class needs to implement an interface for mediation or call.
Similar to observer.
The structure is similar to the event pattern, except that the registration is hardcoded in the intermediary (corresponding to the registration machine in the event), but its idea of solving the problem is a special case of the event, so it is called the intermediary pattern.
Suppose there is one class, and another class that is parallel to the first class in concept (it may be a class that exists from the beginning, or it may be a class that appears as needs change). These two Classes are related. Changes in one class require changes in the state of another class. At this time, a mediator is needed. Specific examples will be introduced in event mode.
4. Spread functions into more classes
In actual projects, it is very troublesome to maintain a "big" class with many functions. This does not comply with the principle of high cohesion and low coupling. If a class has more functions, it will be more process-oriented and the connection between various functions. The closer it is, in fact the main problem that object-oriented has to solve is how to distribute functions into more classes in a more manageable way. It sounds simple, but in fact if the classes are divided in a bad way, it will be more chaotic. In a sense, this is also the reason why design patterns emerged. For example, if a person is responsible for maintaining a class and testing this class, he will have to change the test code of this class every time a function changes. If we distribute the function to more classes, we can ensure that The test code for this class does not change.
1. Event mode ( will write a separate article to introduce it in detail, here is the introduction )
Many people, including me, have the impression that events remain in the window process. When we click the mouse or a button, there will be an event, which will change all objects registered for the event. It may be that the view changes, or it may be ourselves. A defined function, the mediator mode is also similar to the event mode, except that everything registered in the mediator has an equal relationship, such as a table and a histogram. If we change the content of the table, it will cause the histogram to change. We Shortening and lengthening a bar chart changes the contents of the table. But what is the use of event pattern and mediator pattern in general application logic?
We have to put aside the meaning of events mentioned above. The above is just a special case of events. Here is a more general usage of events. In fact, events are essentially a mediator pattern. The mediator places the registered container in the class that needs to be changed, which is equivalent to the object passed into the event in the event. However, some classes were not designed into the mediator pattern at the beginning. , that is to say, the class does not save a member of the mediator. It may be because I did not expect this requirement, or it may be because I think it is troublesome to add this mechanism to the class. Instead, I chose an event pattern that can implement the same function outside the class. . (So the intermediary pattern can be converted into the event pattern. Although the event pattern eliminates the trouble within the class, it needs to provide a set of event mechanisms, which is more troublesome than the intermediary outside the class. However, due to the separation outside the class, there are many ready-made mediator implementations. For example, each framework basically implements this mechanism, and symfony can use this component in frameworks that are not symfony
.In addition to the operation of the view interface above, other examples may not be so intuitive and do not fit the name of the event. Its main function is as written in the title, which is to update the code structure of the event mode. The ability to split code well makes it easier to manage. So to understand it is to forget the general meaning of the event. Consider an example with more complicated logic. A telephone company will calculate the cost based on the user's call records. As we all know, this is a very complex logic. It will differ according to the user's different packages and usage areas. So, there is a long list of logic. Should we write the judgment code in a class? It is definitely not in line with our principles, so we will use the form of the event pattern (repeatedly emphasizing that it is just a form) to divide the logic into different categories. We register all telephone services as listeners, and use if statements to determine which business each call record belongs to. Then we dispatch to those businesses, and the listener obtains the bill object, changes it, and finally The billing object is the final billing information. Through the event model, we separate different processing logic into listener objects, which is more convenient for future expansion.
The above example is to modify the object through the listener, or you can just use the obtained object information to perform related operations. For example, publishing a blog post in the blog park will require many operations, such as the need to save the database, the need to perform inversion operations, and the need to perform For label operations, if you want to publish to the homepage, you also need another series of operations. You can use some listeners to monitor the operation of publishing a blog post. The Post object itself does not modify the Post object, but uses the Post object information to operate.
Back to a more general statement, the event pattern is mainly used in plug-ins, and of course plug-ins in a broader sense. This is an introduction to symfony. Consider the real-world example where you want to provide a plugin system for your project. A plugin should be able to add methods, or do something before or after a method is executed, without interfering with other plugins. This is not an easy problem to solve with single and multiple inheritance (were it possible with PHP) has its own drawbacks.
In the above sense, events are a mechanism for handling and processing objects in a more scalable way. You can use events whenever you want to take advantage of this mechanism, and with the help of event components in the existing framework, You can convert both observers and mediators into event patterns, so events are actually very commonly used and can also be reflected in the emphasis on events in C#.
You can also take a look at the symfony event documentation to learn how to use events.
2. Observer mode
Form: $this->obserber->update($this), and the form of mediator is $this->mediator->chage($this,array('band'=>$newname )). It can be seen that it is just to fulfill two different functional requirements. Both of these can be replaced by events. The former sends an update event, the latter sends a changeBandName event, and then changes are implemented by checking the name of the incoming object.
3. Delegation mode
By assigning or delegating to other objects, the delegation design pattern can remove the decision (if statement) and complex functionality from core objects. Similar to the concept of delegation in C#, C# uses the form of a function to pass the delegate as a parameter to other functions, thereby dividing the functionality into other equations. Delegation in object-oriented is to divide functionality into delegate classes.
Form: There is a member variable of the delegation class in the delegated class.
4. Strategy mode
Best practice is to use the Strategy pattern when it comes to creating interchangeable objects composed of self-contained algorithms that apply to object-based applications.
It is basically the same as the delegation mode, both in form and meaning, except that the delegation mode in the book example passes $this->playlist to the delegation mode, but the strategy mode passes the entire $this to the strategy. model.
Strategy pattern also has an important meaning. If a method of a class is not used frequently, it can be converted into strategy pattern, so that the class does not need to be tested every time during class testing.
5. Agency mode
The proxy mode can have different forms, as long as it is given the meaning of "agency". In the book, agents are implemented through the inheritance form of decorators.
5. Others
The following are very common patterns
1. The inherent object-oriented mode - template mode
I won’t introduce it in detail, it is the same idea as abstract classes and interfaces.
2. Facade
The word facade is very common in the naming of classes in some frameworks. It is similar to the role of function in process-oriented processes. It encapsulates a series of codes for a specific function into a static method in a class. Usually the class only has This is a method.
3. Public methods are abstracted into classes - data access object pattern
It is a basic principle of object-oriented to abstract public methods into classes. It is not just an entity. If a function can be used by multiple entities or functions, then we should form a separate class for it. If other classes use it, it will also This is the dependency injection mentioned above.
The data access object pattern is also the basic practice of this pattern. You can understand it in conjunction with zend famework’s guide http://framework.zend.com/manual/current/en/in-depth-guide/preparing-db-backend.html. Basically, it is to encapsulate data operations. Tablegateway is also a mature model in this field. It is basically a table and a class. However, this also limits the connection operation of the database itself. We can only achieve it through operations between classes. Connection, I will write about it in other articles.
4. Only one is needed in the system - single element mode
This pattern is also very common
6. Notes on key sentences in the book
1. The connection of different objects is the goal of simplification