Heim  >  Artikel  >  Backend-Entwicklung  >  Designmuster: Adaptermuster

Designmuster: Adaptermuster

WBOY
WBOYOriginal
2016-07-30 13:29:25818Durchsuche

Adapter sind leicht zu verstehen. Die meisten Menschen haben zu Hause Handy-Adapter, die zum Aufladen von Mobiltelefonen verwendet werden. Wenn nur ein USB-Anschluss vorhanden ist, kann das Mobiltelefon nicht an einen Standard angeschlossen werden Tatsächlich ist es nicht möglich, das Mobiltelefon an eine Standardsteckdose anzuschließen. Sie müssen einen Adapter verwenden, bei dem ein Ende an den USB-Stecker angeschlossen und das andere Ende an die Steckdose angeschlossen wird Elektrowerkzeuge und modifizieren Sie den USB-Anschluss oder installieren Sie die Buchse neu, aber dies verursacht viel zusätzliche Arbeit und kann dazu führen, dass der Stecker defekt ist. Daher ist die beste Methode, einen Adapter zu finden für die Softwareentwicklung.

Klassenadaptermuster (Vererbung verwenden)

Das Klassenadaptermuster ist sehr einfach, aber im Vergleich zum Objektadaptermuster Das Klassenadaptermuster ist weniger flexibel, da der Adapter (Adapter) die Funktionen vom Adaptee (Adaptee) erbt. Im Konfigurationsmodus muss daher weniger Code geschrieben werden 🎜>

Da der Klassenadaptermodus eine doppelte Vererbung enthält, unterstützt PHP keine doppelte Vererbung. Glücklicherweise kann PHP Schnittstellen verwenden, um eine doppelte Vererbung zu simulieren. Die folgende Struktur erbt nicht nur eine Klasse, sondern erbt auch eine Schnittstelle

class ChildClass extends ParentClass implements ISomeAdapter
{
    
}
Bei der Implementierung des Klassenadaptermusters müssen die Teilnehmer eine PHP-Schnittstelle einbinden

Das Folgende ist ein Währungsumtauschbeispiel zur Veranschaulichung:

Angenommen, es gibt eine Unternehmenswebsite, die gleichzeitig Softwaredienstleistungen und Softwareprodukte verkauft. Derzeit werden alle Transaktionen in den Vereinigten Staaten durchgeführt, also alle Berechnungen Jetzt hoffen die Entwickler, einen Konverter zu haben, der die Umrechnung von US-Dollar und Euro durchführen kann, ohne die ursprüngliche Klasse von Transaktionsbeträgen in US-Dollar zu ändern Euro.

DollarCalc.php

<?php
class DollarCalc
{
    private $dollar;
    private $product;
    private $service;
    public $rate = 1;
    public function requestCalc($productNow, $serviceNow)
    {
        $this->product = $productNow;
        $this->service = $serviceNow;
        $this->dollar = $this->product + $this->service;
        return $this->requestTotal();
    }
    public function requestTotal()
    {
        $this->dollar *= $this->rate;
        return $this->dollar;
    }
}
Wenn Sie sich diese Klasse ansehen, können Sie sehen, dass es ein Attribut $rate gibt. Die Methode requestTotal() verwendet $rate Um den Betrag einer Transaktion zu berechnen, wird dieser Wert auf 1 gesetzt. Tatsächlich muss der Gesamtbetrag nicht auf dem Wechselkurs basieren, aber wenn Sie Kunden Rabatte gewähren oder zusätzliche Dienstleistungen hinzufügen möchten Produkte Gegen eine zusätzliche Gebühr wäre die Variable $rate praktisch. Diese Klasse ist nicht Teil des Adaptermusters, aber sie ist ein Ausgangspunkt.

Anforderungen ändern sich

Da das Unternehmen nun in Europa expandieren möchte, muss es eine Anwendung entwickeln, die die gleiche Berechnung in Euro durchführen kann. Sie möchten, dass diese Euro-Berechnung wie DollarCalc ist. Sie müssen lediglich den Variablennamen ändern.

EuroCalc.php

<?php
class EuroCalc
{
    private $euro;
    private $product;
    private $service;
    public $rate = 1;
    public function requestCalc($productNow, $serviceNow)
    {
        $this->product = $productNow;
        $this->service = $serviceNow;
        $this->euro = $this->product + $this->service;
        return $this->requestTotal();
    }
    public function requestTotal()
    {
        $this->euro *= $this->rate;
        return $this->euro;
    }
}
Fügen Sie als Nächstes den Rest der Anwendung in die EuroCalc-Klasse ein, da alle Daten des Kunden jedoch in USD vorliegen Wenn Sie nicht das gesamte Programm neu entwickeln, können Sie diesen EuroCalc nicht in Ihr System einbinden. Um EuroCalc einzubinden, benötigen Sie jedoch einen Adapter Adapter für europäische Steckdosen können Sie einen Adapter erstellen, der Ihr System in die Lage versetzt, Euro zu verwenden. Zuerst müssen Sie eine Schnittstelle erstellen, die als ITarget bezeichnet wird . Es gibt nur eine Methode requester(). Diese Methode muss durch die spezifische Implementierung der Schnittstelle implementiert werden.

ITarget.php

<?php
interface ITarget
{
    public function requester();
}

Jetzt können Entwickler die requester()-Methode implementieren, um Euro statt Dollar anzufordern.

Im Adapterentwurfsmuster mit Vererbung ist der Adapter ( Adapter)-Teilnehmer implementieren sowohl die ITarget-Schnittstelle als auch die konkrete Klasse EuroCalc. Erstellen Der EuroAdapter erfordert nicht viel Arbeit, da die meiste Arbeit bereits in der EuroCal-Klasse erledigt wurde. Jetzt muss nur noch die Anforderung implementiert werden ()-Methode, damit sie den Dollarwert in den Eurowert umwandeln kann.

EuroAdapter.php

<?php
include_once('EuroCalc.php');
include_once('ITarget.php');
class EuroAdapter extends EuroCalc implements ITarget
{
    public function __construct()
    {
        $this->requester();
    }
    public function requester()
    {
        $this->rate = 0.8111;
        return $this->rate;
    }
}
Im Klassenanpassungsmuster erbt eine konkrete Klasse Eine andere konkrete Klasse ist selten. In den meisten Entwurfsmustern erbt die Klasse ihre abstrakten Methoden und Eigenschaften nach Bedarf erbt die abstrakte Klasse.

Da sie sowohl eine Schnittstelle implementiert als auch die A-Klasse erweitert, verfügt die EuroAdapter-Klasse über diese Schnittstelle und die Schnittstelle der konkreten Klasse Legen Sie den Kurswert (Wechselkurs) fest, damit er die Funktionen des angepassten verwenden und nichts ändern kann.

Definieren Sie unten eine Client-Klasse, um Anfragen von den Klassen EuroAdapter und DollarCalc zu stellen Sehen Sie, der ursprüngliche DollarCalc kann immer noch gut funktionieren, verfügt aber nicht über die ITarget-Schnittstelle

<?php
include_once('EuroAdapter.php');
include_once('DollarCalc.php');
class Client
{
    public function __construct()
    {
        $euro = '&euro;';
        echo "区元: $euro" . $this->makeApapterRequest(new EuroAdapter()) . '<br />';
        echo "美元: $: " . $this->makeDollarRequest(new DollarCalc()) . '<br />';
    }
    private function makeApapterRequest(ITarget $req)
    {
        return $req->requestCalc(40,50);
    }
    private function makeDollarRequest(DollarCalc $req)
    {
        return $req->requestCalc(40,50);
    }
}
$woker = new Client();
Die laufenden Ergebnisse sind wie folgt:

Euros: €72.999
Dollars: $: 90
Sie können sehen, dass Dollar und Euro verarbeitet werden können, das ist der Komfort des Adaptermusters Diese Berechnung ist sehr einfach. Wenn es sich um komplexere Berechnungen handelt, muss die Vererbung die erforderlichen Schnittstellen bereitstellen, um die Zielschnittstelle des Klassenadapters und die spezifische Implementierung festzulegen.

Verwenden Sie die Kombination Adaptermuster

      对象适配器模式使用组合而不是继承, 不过它也会完成同样的目标. 通过比较这两个版本的适配器模式, 可以看出它们各自的优缺点. 采用类适配器模式时,适配器可以继承它需要的大多数功能, 只是通过接口稍微调. 在对象适配器模式中 适配器(Adapter)参与使用被适配者(Adaptee), 并实现Target接口. 在类适配器模式中, 适配器(Adapter)则是一个被适配者(Adaptee), 并实现Target接口.

示例: 从桌面环境转向移动环境

PHP程序员经常会遇到这样一个问题:需要适应移动环境而做出调整.不久之前,你可能只需要考虑提供一个网站来适应多种不同的桌面环境. 大多数桌面都使用一个布局, 再由设计人员让它更美观. 对于移动设备, 设计人员和开发人员不仅需要重新考虑桌面和移动环境中页面显示的设计元素, 还要考虑如何从一个环境切换到另一个环境.

首先来看桌面端的类Desktop(它将需要一个适配器). 这个类使用了一个简单但很宽松的接口:

IFormat.php

<?php
interface IFormat
{
    public function formatCSS();
    public function formatGraphics();
    public function horizontalLayout();
}

它支持css和图片选择, 不过其中一个方法指示一种水平布局, 我们知道这种布局并不适用小的移动设备.下面给出实现这个接口的Desktop类

Desktop.php

<?php
include_once('IFormat.php');
class Desktop implements IFormat
{
    public function formatCSS()
    {
        echo "引用desktop.css<br />";
    }
    public function formatGraphics()
    {
        echo "引用desktop.png图片<br />";
    }
    public function horizontalLayout()
    {
        echo '桌面:水平布局';
    }
}

问题来了, 这个布局对于小的移动设备来说太宽了. 所以我们的目标是仍采用同样的内容, 但调整为一种移动设计.

下面来看移动端的类Mobile

首先移动端有一个移动端的接口

IMobileFormat

<?php
interface IMobileFormat
{
    public function formatCSS();
    public function formatGraphics();
    public function verticalLayout();
}

可以看到, IMobileFormat接口和IFormat接口是不一样的,也就是不兼容的, 一个包含了方法horizontalLayout(), 另一个包含方法verticalLaout(), 它们的差别很小, 最主要的区别是: 桌面设计可以采用水平的多栏布局, 而移动设计要使用垂直布局,而适配器就是要解决这个问题

下面给出一个实现了IMoibleFormat接口的Mobile类

Mobile.php

<?php
include_once('IMobileFormat.php');
class Mobile implements IMobileFormat
{
    public function formatCSS()
    {
        echo "引用mobile.css<br />";
    }
    public function formatGraphics()
    {
        echo "引用mobile.png图片<br />";
    }
    public function verticalLayout()
    {
        echo '移动端:垂直布局';
    }
}

Mobile类和Desktop类非常相似, 不过是图片和CSS引用不同

接下来,我们需要一个适配器,将Desktop和Mobile类结合在一起

MobileAdapter.php

<?php
include_once('IFormat.php');
include_once('Mobile.php');
class MobileAdapter implements IFormat
{
    private $mobile;
    public function __construct(IMobileFormat $mobileNow)
    {
        $this->mobile = $mobileNow;
    }
    public function formatCSS()
    {
        $this->mobile->formatCSS();
    }
    public function formatGraphics()
    {
        $this->mobile->formatGraphics();
    }
    public function horizontalLayout()
    {
        $this->mobile->verticalLayout();
    }
}

可以看到,MobileAdapter实例化时要提供一个Mobile对象实例.还要注意 ,类型提示中使用了IMobileFormat, 确保参数是一个Mobile对象.有意思的是, Adapter参与者通过实现horizontalLayout()方法来包含verticalLayout()方法.实际上, 所有MobileAdapter方法都包装了一个Mobile方法.碰巧的是, 适配器参与者中的一个方法并不在适配器接口中(verticalLayout());它们可能完全不同, 适配器只是把它们包装在适配器接口(IFormat)的某一方法中.

客户调用(Client)

Client.php

<?php
include_once('Mobile.php');
include_once('MobileAdapter.php');
class Client
{
    private $mobile;
    private $mobileAdapter;
    public function __construct()
    {
        $this->mobile = new Mobile();
        $this->mobileAdapter = new MobileAdapter($this->mobile);
        $this->mobileAdapter->formatCSS();
        $this->mobileAdapter->formatGraphics();
        $this->mobileAdapter->horizontalLayout();
    }
}
$worker = new Client();

适配器模式中的Client类必须包装Adaptee(Mobile)的一个实例, 以便集成到Adapter本身.实例化Adapter时, Client使用Adatee作为参数来完成Adapter的实例化.所以客户必须首先创建一个Adapter对象(new Mobile()), 然后创建一个Adapter((new MobileAdapter($this->mobile)).

Client类的大多数请求都是通过MobileAdapter发出的. 不过这个代码的最后他使用了Mobile类的实例.

适配器和变化

      PHP程序员要即该面对变化.不同版本的PHP会变化, 可能增加新的功能, 另外还可能取消一些功能.而且随着PHP的大大小小的变化,MySQL也在改变.例如, mysql的扩展包升级为mysqli, PHP开发人员需要相应调整, 要改为使用mysqli中的新API.这里适合采用适配器模式吗?可能不适合.适配器可能适用, 可能不适用,这取决于你的程序如何配置.当然可以重写所有连接和交互代码, 不过这可不是适配器模式的本意, 这就像是重新安装USB连接头, 想把它插进标准的墙上插座一样. 不过, 如果所有原来的mysql代码都在模块中, 你可以修改这个模块(类),换入一个有相同接口的新模块.只是要使用mysqli而不是mysql.我不认为交换等同于适配器, 不过道理是一样的, 在适配器模式中, 原来的代码没有任何改变, 有变化的只是适配器.

如果需要结合使用两个不兼容的接口, 这种情况下, 适配器模式最适用.适配器可以完成接口的"联姻".可以把适配器看作是一个婚姻顾问;通过创建一个公共接口来克服双方的差异.利用 这种设计模式, 可以促成二者的合作,而避免完全重写某一部分.

以上就介绍了设计模式之:适配器模式,包括了方面的内容,希望对PHP教程有兴趣的朋友有所帮助。

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn