Have you ever wondered what design patterns are? This article will explain why design patterns are essential, and some PHP examples will be given explaining when and where they should be used.
Design patterns are reusable, optimized solutions to the programming problems that we face every day. A design pattern is not a class or library that we can simply insert into our system. He is much more. This is some kind of template that should be implemented in the proper situation. It does not depend on the language. A good design pattern should be such that it can be used with most (if not all) languages ​​depending on the characteristics of the language. It is extremely important that any design pattern needs to be used very carefully - if it is applied in an inappropriate place, then its action can be destructive and cause many problems for you. However, when applied at the right place at the right time, it can be your savior.
There are three main types of design patterns:
• structural
• generating
• behavioral
')
Structural patterns, in general, deal with relationships between objects, facilitating their work together.
Generating templates provide instantiation mechanisms, making it easy to create objects in a way that best suits the situation.
Behavioral patterns are used in communication between objects, making it easier and more flexible.
Why should they be used?
Design patterns in principle are well thought out solutions to programming problems. Many programmers have previously encountered these problems and used to overcome these "solutions". Encountering some problem, why re-seek a solution when you can apply an already proven one?
Example
Let's imagine that you are tasked with creating a way to combine two classes that perform two different actions depending on the situation. These two classes are intensively used by the existing system in different places, which makes it difficult to delete them and modify the existing code. In addition, the modification of the existing code requires verification of the entire modified code, since editing of this kind in a system built on different components almost always introduces new errors. Instead of the above, you can use a variant of the “Strategy” template and the “Adapter” template, which can easily handle the types of scripts mentioned.
01 <?php 02 class StrategyAndAdapterExampleClass { 03 private $_class_one; 04 private $_class_two; 05 private $_context; 06 07 public function __construct( $context ) { 08 $this->_context = $context; 09 } 10 11 public function operation1() { 12 if( $this->_context == "context_for_class_one" ) { 13 $this->_class_one->operation1_in_class_one_context(); 14 } else ( $this->_context == "context_for_class_two" ) { 15 $this->_class_two->operation1_in_class_two_context(); 16 } 17 } 18 }
Pretty simple, isn't it? Now let's take a closer look at the “Strategy” template.
Template "Strategy"
Image hosted with permission from the owners of the site cioinnervoice.wordpress.com
The Strategy template is a behavioral design template that allows you to decide which action plan a program should adopt based on a specific context in which it is executed. You lay down two different algorithms within the two classes and decide in the course of execution which strategy you should work with.
In our example above, the strategy is set depending on what the
$ context variable was at the time the class was processed. If you give it context for a
single class , one will be used and vice versa.
Great, but where can I use it?
Suppose you are currently developing a class that can either update or create a new user record. Although he needs the same inputs (name, address, mobile phone number, etc.), depending on the situation, he must use different functions when updating and creating. Here you can probably use the conditional “if-else” transition immediately, but what if you need this class in another place? Then it will be necessary to rewrite completely this entire conditional statement. Wouldn't it be easier to just point out your context?
01 <?php 02 class User { 03 04 public function CreateOrUpdate($name, $address, $mobile, $userid = null) 05 { 06 if( is_null($userid) ) { 07
Now, the “usual” “Strategy” pattern implies placing your algorithms inside another class, but in this case another class would be an irrational decision. Remember that you do not have to follow the pattern exactly. Options work while the concept remains the same, and this solves the problem.
Template "Adapter"
Image hosted by permission of the owners of the site
www.uxcell.com
The “Adapter” template is a structural design template that allows you to repurpose a class with a different interface, making it accessible to a system that uses various calling methods.
It also allows you to modify some of the inputs received from the client class, turning it into something compatible with the functions of the Adaptee class.
How can I use it?
Another concept for referring to an adapter class is
“wrapper,” which essentially allows you to “wrap” actions into a class and reuse these actions in appropriate situations. A classic example would be the creation of a domain class for classes of tables. Instead of calling various classes of tables and sequentially calling their functions, you can nest all these methods into one using an adapter class. This not only allows you to reuse any required actions, but also eliminates the need to rewrite the code if you need to use the same action elsewhere.
Compare these two implementations:
Approach without adapter
1 <?php 2 $user = new User(); 3 $user->CreateOrUpdate(
If we had to do it again in another place or even use this code in another project, then we would have to type it all over again.
It is better
Specified opposite to actions like the ones below:
1 <?php 2 $account_domain = new Account(); 3 $account_domain->NewAccount(
In this situation, we have a wrapper class, which would be our domain class Account:
01 <?php 02 class Account() 03 { 04 public function NewAccount( //inputs ) 05 { 06 $user = new User(); 07 $user->CreateOrUpdate(
Thus, you can use the Account domain again, wherever required, - in addition, you will be able to wrap other classes under your domain class as well.
Template "Factory Method"
Image hosted by permission of the owners of the site www.lankanewspappers.com
The Factory Method pattern is a design-generating pattern that does exactly what that word means: this class acts as a factory of instantiated objects.
The main purpose of this pattern is to nest a generating procedure that can reduce various classes into one function. If the factory method is provided with the proper context, it will be able to return the correct object.
When can I use it?
The best situation to use the “Factory Method” template is to have several different variants of the same object. Suppose there is a class "button"; This class has various options — for example, ImageButton (image button), InputButton (input button), and FlashButton (flash button). Depending on the location, you may need to create different buttons - this is where you can use the “factory” to create buttons for you!
Let's start by creating our three classes:
01 <?php 02 abstract class Button { 03 protected $_html; 04 05 public function getHtml() 06 { 07 return $this->_html; 08 } 09 } 10 11 class ImageButton extends Button { 12 protected $_html = "...";
Now you can create our factory class:
01 <?php 02 class ButtonFactory 03 { 04 public static function createButton($type) 05 { 06 $baseClass = 'Button'; 07 $targetClass = ucfirst($type).$baseClass; 08 09 if (class_exists($targetClass) && is_subclass_of($targetClass, $baseClass)) { 10 return new $targetClass; 11 } else { 12 throw new Exception("The button type '$type' is not recognized."); 13 } 14 } 15 }
The resulting code can be used, for example, as follows:
1 $buttons = array('image','input','flash'); 2 foreach($buttons as $b) { 3 echo ButtonFactory::createButton($b)->getHtml() 4 }
The output should be HTML of all your button types. That way, you could specify which button to create depending on the situation, as well as reuse the condition.
Template "decorator"
Image hosted by permission of the owners of the site www.decoratorsdarlington.co.uk
The decorator pattern is a structural design pattern that allows us to add new or additional behavior to an object during execution, depending on the situation.
The goal is to make it so that extended functions can be applied to one specific instance and at the same time be able to create an original instance that does not have these new functions. It also allows you to combine multiple decorators for one instance, so there is no binding to one decorator for each instance. This template is an alternative to creating a subclass that refers to creating a class that inherits the functionality from the parent class. In contrast to creating a subclass that adds behavior at compile time, “decorating” allows you to add new behavior at runtime if the situation requires it.
To implement the Decorator pattern, you can perform the following steps:
1. Select the original “Component” class as a subclass of the “Decorator” class.
2. In the Decorator class, add the Component pointer as a field.
3. Move the “Component” to the “Decorator” constructor to initialize the “Component” pointer.
4. In the Decorator class, redirect all the Component methods to the Component pointer.
5. In the "Decorator" class, cancel any method (any methods) "Component" whose behavior (s) should be modified.
These steps are posted with the permission of the owners of the site en.wikipedia.org/wiki/Decorator_pattern
When can I use it?
It is most convenient to use the “Decorator” template for an object that requires a new behavior only when there is a request for a situation. Suppose there is an HTML layout element, a link to logout, and you want it to do slightly different actions based on the current page. To do this, you can use the template "Decorator".
First, we define the various required “decorations”:
• If we are on the main page and registered, then this link should be “wrapped” in h2 tags.
• If we are on another page and registered, then this link must be wrapped in underscore tags.
• If we are registered, this link must be wrapped in bold tags.
After setting our "scenery" you can program them:
01 <?php 02 class HtmlLinks { 03 // , html- 04 } 05 06 class LogoutLink extends HtmlLinks { 07 protected $_html; 08 09 public function __construct() { 10 $this->_html = "<a href=\"logout.php\">Logout</a>"; 11 } 12 13 public function setHtml($html) 14 { 15 $this->_html = $html; 16 } 17 18 public function render() 19 { 20 echo $this->_html; 21 } 22 } 23 24 class LogoutLinkH2Decorator extends HtmlLinks { 25 protected $_logout_link; 26 27 public function __construct( $logout_link ) 28 { 29 $this->_logout_link = $logout_link; 30 $this->setHtml("<h2>" . $this->_html . "</h2>"); 31 } 32 33 public function __call( $name, $args ) 34 { 35 $this->_logout_link->$name($args[0]); 36 } 37 } 38 39 class LogoutLinkUnderlineDecorator extends HtmlLinks { 40 protected $_logout_link; 41 42 public function __construct( $logout_link ) 43 { 44 $this->_logout_link = $logout_link; 45 $this->setHtml("<u>" . $this->_html . "</u>"); 46 } 47 48 public function __call( $name, $args ) 49 { 50 $this->_logout_link->$name($args[0]); 51 } 52 } 53 54 class LogoutLinkStrongDecorator extends HtmlLinks { 55 protected $_logout_link; 56 57 public function __construct( $logout_link ) 58 { 59 $this->_logout_link = $logout_link; 60 $this->setHtml("<strong>" . $this->_html . "</strong>"); 61 } 62 63 public function __call( $name, $args ) 64 { 65 $this->_logout_link->$name($args[0]); 66 } 67 }
Then we should be able to use it, for example, as follows:
01 $logout_link = new LogoutLink(); 02 03 if( $is_logged_in ) { 04 $logout_link = new LogoutLinkStrongDecorator($logout_link); 05 } 06 07 if( $in_home_page ) { 08 $logout_link = new LogoutLinkH2Decorator($logout_link); 09 } else { 10 $logout_link = new LogoutLinkUnderlineDecorator($logout_link); 11 } 12 $logout_link->render();
Here you can see how we are able to combine several decorators, if required. Since all decorators use the magic function
__call , we can still call the methods of the original function. If we accept that we are currently inside the main page and registered, then the HTML output should be as follows:
1 <strong><h2><a href="logout.php">Logout</a></h2></strong>
Template "Single"
Image hosted with permission of the owners of intoxicologist.wordpress.com
The Singleton design pattern is a design-originating pattern that ensures that there is only one instance of a particular class at run time and a global access point to this single instance.
This makes it easier to set the “coordination” point for other objects that also use this single instance, since its variables will be unchanged for any calls.
When can I use it?
If you need to translate a specific instance from one class to another, you can use the “Singleton” template to eliminate the passage of this instance through a constructor or argument. Suppose you create a Session class that simulates the $ _SESSION global array. Since for this class its instance needs to be created only once, it is possible to implement the “Singleton” template, for example:
01 <?php 02 class Session 03 { 04 private static $instance; 05 06 public static function getInstance() 07 { 08 if( is_null(self::$instance) ) { 09 self::$instance = new self(); 10 } 11 return self::$instance; 12 } 13 14 private function __construct() { } 15 16 private function __clone() { } 17 18
By doing so, we can access our session instance from various parts of our code, even in different classes. This data will be maintained for all getInstance calls.
Conclusion
There are still many design patterns that are useful to know; in this article, I dwelt on only some of the most famous ones that I use when programming. If you are interested in reading about other design patterns, the
Design Patterns Wikipedia page contains a lot of information about it. If this is not enough, then you can always read the book
Design Patterns: Elements of Reusable Object-Oriented Software (
Design Patterns: Elements of Reusable Object-Oriented Software ), which is considered one of the best on the subject.
And the last thing: using these design patterns, always check that you are trying to solve the right task. As I mentioned earlier, these design patterns should be used very carefully: they can worsen the situation when used in the wrong context, but if used correctly, they are simply vital.
If you found this article useful, then why not familiarize yourself with the
PHP scripts offer on the Envato Market. There are thousands of useful scripts that can speed up your development and improve the final result. There are
reservation systems ,
AJAX contact forms ,
newsletter systems and more.