Design patterns
アダプタ
サーチ…
アダプタパターン(PHP)
異なるタイプの組織で特定のルーチンが実行される科学実験を使用した実際の世界の例。クラスには、ティッシュまたはルーチンを別々に取得するために、デフォルトで2つの関数が含まれています。それ以降のバージョンでは、新しいクラスを使用してそれを適用し、両方を取得する関数を追加しました。つまり、元のコードを編集していないため、既存のクラスを破る危険性はなく(再テストも必要ありません)。
class Experiment {
private $routine;
private $tissue;
function __construct($routine_in, $tissue_in) {
$this->routine = $routine_in;
$this->tissue = $tissue_in;
}
function getRoutine() {
return $this->routine;
}
function getTissue() {
return $this->tissue;
}
}
class ExperimentAdapter {
private $experiment;
function __construct(Experiment $experiment_in) {
$this->experiment = $experiment_in;
}
function getRoutineAndTissue() {
return $this->experiment->getTissue().' ('. $this->experiment->getRoutine().')';
}
}
アダプタ(Java)
あなたの現在のコードベースにはMyLogger
インターフェースが存在すると仮定します。
interface MyLogger {
void logMessage(String message);
void logException(Throwable exception);
}
MyFileLogger
やMyConsoleLogger
など、いくつかの具体的な実装を作成したとします。
アプリケーションのBluetooth接続を制御するフレームワークを使用することに決めました。このフレームワークには、次のコンストラクタを持つBluetoothManager
が含まれています。
class BluetoothManager {
private FrameworkLogger logger;
public BluetoothManager(FrameworkLogger logger) {
this.logger = logger;
}
}
BluetoothManager
はロガーも受け付けます。これは素晴らしいことです!しかし、フレームワークによってインタフェースが定義されたロガーが必要であり、関数の名前を変更する代わりにメソッドのオーバーロードが使用されています。
interface FrameworkLogger {
void log(String message);
void log(Throwable exception);
}
再利用したいMyLogger
実装がすでにありますが、 FrameworkLogger
インターフェースには適合しません。これは、アダプターのデザインパターンが入る場所です。
class FrameworkLoggerAdapter implements FrameworkLogger {
private MyLogger logger;
public FrameworkLoggerAdapter(MyLogger logger) {
this.logger = logger;
}
@Override
public void log(String message) {
this.logger.logMessage(message);
}
@Override
public void log(Throwable exception) {
this.logger.logException(exception);
}
}
FrameworkLogger
インターフェイスを実装し、 MyLogger
実装を受け入れるアダプタクラスを定義することによって、異なるインターフェイス間で機能をマッピングできます。これで、 MyLogger
すべての実装でBluetoothManager
を使用することができます。
FrameworkLogger fileLogger = new FrameworkLoggerAdapter(new MyFileLogger());
BluetoothManager manager = new BluetoothManager(fileLogger);
FrameworkLogger consoleLogger = new FrameworkLoggerAdapter(new MyConsoleLogger());
BluetoothManager manager2 = new BluetoothManager(consoleLogger);
Javaの例
Adapterパターンの素晴らしい既存の例は、SWTで見つけることができるのMouseListenerとMouseAdapterのクラス。
MouseListenerインタフェースは次のようになります。
public interface MouseListener extends SWTEventListener {
public void mouseDoubleClick(MouseEvent e);
public void mouseDown(MouseEvent e);
public void mouseUp(MouseEvent e);
}
ここで、UIを構築してこれらのリスナーを追加するシナリオを想像してください。しかし、何かがシングルクリックされたとき(mouseUp)以外のことは気にしません。あなたは空の実装を絶えず作成したくないでしょう:
obj.addMouseListener(new MouseListener() {
@Override
public void mouseDoubleClick(MouseEvent e) {
}
@Override
public void mouseDown(MouseEvent e) {
}
@Override
public void mouseUp(MouseEvent e) {
// Do the things
}
});
代わりに、MouseAdapterを使用することができます:
public abstract class MouseAdapter implements MouseListener {
public void mouseDoubleClick(MouseEvent e) { }
public void mouseDown(MouseEvent e) { }
public void mouseUp(MouseEvent e) { }
}
空のデフォルトの実装を提供することで、私たちがアダプタから気にかけているメソッドだけを自由にオーバーライドすることができます。上記の例から、
obj.addMouseListener(new MouseAdapter() {
@Override
public void mouseUp(MouseEvent e) {
// Do the things
}
});
アダプタ(UMLとその例)
より多くの想像力を持たせることができるときにアダプターパターンと状況の種類を使用するために、ここでは小さく、シンプルで非常に具体的な例を示します。ここにはコードはなく、UMLだけでなく、例の状況とその問題の説明もあります。確かに、UMLコンテンツはJavaのように書かれています。 (ヒントテキストには「良い例はほとんどがコードです」と書かれていますが、デザインパターンは抽象的で、別の方法でも導入できると思います)。
通常、アダプタパターンは、互換性のないインターフェイスがあり、そのいずれも直接書き換えることができない状況に適したソリューションです。
素敵な小さなピザ宅配サービスを行っているとします。顧客はあなたのウェブサイトでオンラインで注文することができますし、クラスPizza
を使用して小規模なシステムを持ち、 Pizza
を表現し、請求書、税務レポートなどを計算します。あなたのピザの価格は、(あなたが選んだ通貨の)セントで価格を表す単一の整数として与えられます。
あなたのデリバリーサービスはすごくうまくいっていますが、ある時点では、あなた自身の顧客の増加に対応することはできませんが、まだ拡大したいと考えています。大きなオンラインのメタデリバリーサービスのメニューにピザを追加することにしました。彼らはピザだけでなく多くの異なる食事を提供しているので、彼らのシステムは抽象化をより多く使用し、お金を表すクラスMoneyAmount
と共に食事を表すインターフェースIMeal
を持っています。
MoneyAmount
は入力として2つの整数で構成され、1つはコンマの前の金額(またはランダムな通貨)で、もう1つはコンマの後の0から99までのセントの金額です。
Pizza
の価格は合計価格をセント(> 99)の額として表す単一の整数であるため、 IMeal
互換性はありません。これは、アダプターパターンが出現するポイントです。自分のシステムを変更したり、新しいシステムを作成するのに多大な労力を要し、互換性のないインターフェースを実装する必要がある場合は、アダプターpattternを適用することができます。
パターンを適用するには、クラスアダプタとオブジェクトアダプタの2つの方法があります。
両方とも、アダプター( PizzaAdapter
)は、新しいインターフェースとアダプター(この例ではPizza
)の間で何らかのPizzaAdapter
として機能するという共通点があります。アダプターは新しいインターフェース( IMeal
)を実装し、次にPizza
を継承し、独自の価格を1つの整数から2(クラス・アダプター)に変換します。
または属性としてPizza
型のオブジェクトを持ち、その値(オブジェクトアダプタ)を変換します。
アダプターパターンを適用すると、互換性のないインターフェース間で「翻訳」することになります。