PHP design pattern (5) adapter mode

Time:2020-11-19

This article describes the PHP design pattern: adapter pattern adapter. For your reference, the details are as follows:

1. Overview:

         Interface change is a common problem that programmers have to accept and deal with (though reluctantly). Program providers modify their code; system libraries are modified; various programming languages and related libraries develop and evolve.

        Example 1: iPhone 4, you can use the UBS interface to connect the computer to charge. If only the iPhone does not have a computer, what to do? Apple provides an iPhone power adapter. You can use this power adapter to charge. The power adapter of this iPhone is similar to the adapter mode we call it. (the power adapter is to change the power supply into the required voltage, that is, the function of the adapter is to make one thing suitable for another.)

       Example 2: the most typical example is many functional mobile phones. Each model has its own slave devices. One day, its own charger is broken, and there is no such charger available in the market. What should I do? Universal charger can solve this problem. This universal charger is the adapter.

2. Problems

How do you avoid the inconvenience caused by API changes in external libraries? If you write a library, can you provide a way to allow existing users of your software to upgrade perfectly, even if you have changed your API? How do you change the interface of an object to better suit your needs?

3. Solutions

The adapter pattern provides an entirely different interface for objects. You can use the adapter to implement a common interface of a different class, while avoiding disputes caused by upgrading and disassembling customer code.

The adapter pattern transforms the interface of a class into another interface expected by the client. The adapter pattern enables two classes that could not work together due to interface mismatch (or incompatibility) to work together. Also known as converter mode, transformer mode, wrapper mode (package some existing classes, so that they can meet the needs of the interface).
Consider when (not hypothetical! )What happens when the API of a third-party library changes. In the past, you had to grit your teeth to modify all the customer code, and the situation was not so simple. You may be working on a new project that uses the features of the new version of the library, but you already have a lot of old applications that interact well with previous versions of the library. You will not be able to prove the value of these new features if this upgrade means that customer code for other applications will be involved.

4. Classification

There are two types of adapter patterns: 1. Adapter pattern of class (implemented by inheritance); 2. Object adapter (implemented by object composition)

1) Class adapter pattern — the adapter inherits the class it implements (generally multiple inheritance).

Adapter and Adaptee are inheritance relations

1. Match with a specific adapter class and target. The result is that when we want to match a class and all its subclasses, the class adapter will not be able to do the job
2. This enables the adapter to redefine part of the behavior of Adaptee, because adapter is a subset of Adaptee
3. Only an object is introduced, and no additional pointer is needed to obtain Adaptee indirectly
2) Object adapter pattern — the adapter holds an instance of the class it encapsulates. In this case, the adapter calls the physical entity of the wrapped object.

Adapter and Adaptee are delegation relations

1. Allows one adapter to work with more than one adapter at the same time. The adapter can also add functions to all adapters at once
2. It is difficult to use the behavior of redefining Adaptee
No matter what kind of adapter, its purpose is: to retain the services provided by existing classes and provide interfaces to customers to meet their expectations.
That is to provide new interface services without changing the original system.

Applicability 5

The adapter mode is used when:

1. You want to use an existing class, but its interface does not meet your requirements.
2. You want to create a reusable class that can work with other unrelated or unforeseen classes (that is, classes whose interfaces may not be compatible).
3 · (object adapter only) you want to use some existing subclasses, but it is not possible to subclass each to match their interface. The object adapter can adapt to its parent class interface. In other words, only an object is introduced, and no additional pointer is needed to obtain Adaptee indirectly.

6. Structure

The class adapter uses multiple inheritance to match one interface with another, as shown in the following figure:

Object dependent, as shown in the following figure:

7. Composition of construction mode

· target: defines the domain specific interfaces used by the client.
· client: works with objects that conform to the target interface.
· Adaptee: defines an interface that already exists and has been used, which needs to be adapted.
Adapter: the core of the adapter pattern. It converts the existing interface of the adapted Adaptee role to the target role target matching interface. The interface of Adaptee is adapted to target interface

8. Effect

There are different trade-offs between class adapters and object adapters.

Class Adapter

Match Adaptee and target with a specific adapter class. The result is that when we want to match a class and all its subclasses, the class adapter won’t do the job.
It enables the adapter to redefine part of the behavior of Adaptee, because adapter is a subclass of Adaptee.
· only one object is introduced, and no additional pointer is needed to get the Adaptee indirectly.

Object adapter

Allow an adapter to work with multiple adaptees – that is, the Adaptee itself and all its subclasses (if any) – at the same time. The adapter can also add functions to all adapters at once.
It makes it difficult to redefine the behavior of Adaptee. This needs to generate a subclass of Adaptee and make the adapter refer to this subclass rather than the Adaptee itself.

Some other factors to consider when using the adapter mode are:

1) The matching degree of adapter the workload of matching the interface of Adaptee with that of target may be different for each adapter. The scope of work may range from simple interface transformations (such as changing the operation name) to supporting a completely different set of operations. The workload of the adapter depends on the similarity between the target interface and the Adaptee interface
2) Pluggable adapter when other classes use a class, the less assumptions are required, the more reusable the class is. If you build an interface match as a class,
There is no need to assume that the same interface is visible to other classes. In other words, interface matching enables us to add our own classes to some existing systems,
These systems may have different interfaces to this class.  
3) A potential problem with using adapters is that they are not transparent to all customers. The adapted object is no longer compatible with the adapter interface,
Therefore, not all Adaptee objects can be used where they can be used. Bidirectional adapters provide such transparency.
Bidirectional adapters are especially useful when two different customers need to view the same object in different ways.

9. Implementation

Class adapters use inheritance

Let’s look at how to protect the application from being affected when the API changes.

<?php
/**
 *Class adapter pattern
 * @author guisu
 * 
 */
 
/**
 *Target role
 * @version 1.0
 */
class Target {
 
  /**
   *This method may be improved in the future
   */
  public function hello(){
   echo 'Hello ';
  }
 
  /**
   *Target point
   */
  public function world(){
   echo 'world';
  }
}
 
/**
 *Client program
 *
 */
class Client {
 
  /**
   * Main program.
   */
  public static function main() {
    $Target = new Target();
    $Target->hello();
    $Target->world();
 
  }
 
}
Client::main();
?>

Target has made it clear that the hello () method will be improved in future versions, even not supported or eliminated. Next, let’s assume that the second version of target has been released. A new green () method replaces hello().

<?php
/**
 *Class adapter pattern
 * @author guisu
 * 
 */
 
/**
 *Target role
 * @version 2.0
 */
class Target {
 
  /**
   *This method is likely to be improved in the future
   */
  public function greet(){
   echo 'Greet ';
  }
 
  /**
   *Target point
   */
  public function world(){
   echo 'world';
  }
}

If we continue to use the original client code, we will definitely report an error and cannot find the Hello method.

The solution to API “upgrade” is to create an adapter.

The class adapter uses inheritance:

<?php
/**
 *Class adapter pattern
 * @author guisu
 * 
 */
 
/**
 *Target role
 * @version 2.0
 */
interface Target {
 
  /**
   *Method of the source class: this method is likely to be improved in the future
   */
  public function hello();
 
  /**
   *Target point
   */
  public function world();
}
 
/**
 *Source character: adapted character
 */
class Adaptee {
 /**
   *Methods contained in source classes
   */
  public function world() {
    echo ' world <br />';
  }
 
  /**
   *Adding new methods
   */
  public function greet() {
    echo ' Greet ';
  }
}
 
/**
 *Class adapter role
 */
class Adapter extends Adaptee implements Target {
 
  /**
   *There is no world method in the source class
   */
  public function hello() {
    parent::greet();
  }
 
}
/**
 *Client program
 *
 */
class Client {
 
  /**
   * Main program.
   */
  public static function main() {
    $adapter = new Adapter();
    $adapter->hello();
    $adapter->world();
  }
}
Client::main();
?>

The object adapter uses delegation

<?php
/**
 *Class adapter pattern
 * @author guisu
 * 
 */
 
/**
 *Target role
 * @version 2.0
 */
interface Target {
 
  /**
   *Method of the source class: this method is likely to be improved in the future
   */
  public function hello();
 
  /**
   *Target point
   */
  public function world();
}
 
/**
 *Source character: adapted character
 */
class Adaptee {
 /**
   *Methods contained in source classes
   */
  public function world() {
    echo ' world <br />';
  }
 
  /**
   *Adding new methods
   */
  public function greet() {
    echo ' Greet ';
  }
}
 
/**
 *Class adapter role
 */
class Adapter implements Target {
 
 private $_adaptee;
 /**
  * construct
  *
  * @param Adaptee $adaptee
  */
  public function __construct(Adaptee $adaptee) {
    $this->_adaptee = $adaptee;
  }
 
  /**
   *There is no world method in the source class
   */
  public function hello() {
    $this->_adaptee->greet();
  }
 
  /**
   *There is no world method in the source class
   */
  public function world() {
    $this->_adaptee->world();
  }
}
/**
 *Client program
 *
 */
class Client {
 
  /**
   * Main program.
   */
  public static function main() {
   $adaptee = new Adaptee();
    $adapter = new Adapter($adaptee);
    $adapter->hello();
    $adapter->world();
  }
}
Client::main();
?>

As the code in the example shows, you can use the adapter pattern to avoid the inconvenience of external library changes – if upward compatible. As a developer of a library, you should write an adapter independently to make it easier for your users to use the new version of the library without modifying all their existing code.

The adapter pattern proposed in GoF book tends to use inheritance rather than composition. This is advantageous in strongly typed languages, because the adapter is actually a subclass of the target class, and therefore can be better combined with methods in the class.

For better flexibility, I prefer composition methods (especially when combined with dependency inversion); however, inherited methods provide two versions of the interface, which may be a key to improving flexibility in your practical application.

10. Adapter mode and other related modes

Bridge mode:The bridge pattern is similar to the object adapter, but the starting point of the bridge pattern is different: the purpose of the bridge pattern is to separate the interface part from the implementation part, so that they can be changed easily and relatively independently. The object adapter pattern means changing the interface of an existing object

Decorator Pattern: decorator mode enhances the functionality of other objects without changing their interfaces. Therefore, the decoration mode is more transparent to the application than the adapter. The result is that decorator pattern supports recursive composition, which is not possible with adapters alone.

Facade:The focus of the adapter pattern is to change the API of a single class. The purpose of facade is to provide a more concise interface for the whole subsystem composed of many objects. The adapter pattern encapsulates a separate class. The adapter pattern is often used when the third-party API is required to work together, trying to isolate your code from the third-party library.

Both adapter mode and appearance mode are encapsulation of existing system. But the intention of the two modes is completely different. The former makes the existing system work with the system under design, while the latter provides a more convenient access interface for the existing system. Simply put, the adapter pattern is designed after the fact, while the appearance mode must be designed in advance, because the system depends on the appearance. In short, the adapter pattern does not introduce a new interface, whereas the facade pattern defines a completely new interface.

Proxy modeA proxy is defined for another object without changing its interface.

The differences among decorator mode, adapter mode and appearance mode are as follows

In decorator mode, it will not change the interface, but decorate the interface one by one, that is to add new functions.

The adapter pattern is to indirectly convert one interface to another through adaptation.

Appearance mode, it is mainly to provide a clean and consistent interface to the client.

More about PHP related content interested readers can see this site topic: “PHP object-oriented programming introductory tutorial”, “PHP array (array) operation skills”, “PHP basic syntax introductory course”, “PHP operation and operator Usage Summary”, “PHP character string (string) Usage Summary”, “PHP + MySQL database operation introduction tutorial” and “PHP common database operation” Summary skills

I hope this article will help you with PHP programming.

Recommended Today

Explain module, import and export in JavaScript

Author: Tania rascia Crazy technology house Original text:https://www.taniarascia.com/j… In the era of the Internet, websites are mainly developed with HTML and CSS. If you load JavaScript into a page, it usually provides effects and interactions in the form of small fragments. Generally, all JavaScript code is written in a file and loaded into a filescriptTag. […]