今日のトピックは「アダプタパターンとデコレータパターン」です。アダプタパターンとデコレータパターンは、デザインパターンの中でも広く使われている2つのパターンです。アダプタパターンは、異なるインターフェースを持つクラス同士を接続するために使用され、デコレータパターンはオブジェクトに動的に機能を追加するために使用されます。これらのパターンを理解し、適切に使い分けることで、より柔軟で保守性の高いコードを実装することが可能になります。
目次
基本概念の説明
アダプタパターン (Adapter Pattern)
アダプタパターンは、既存のクラスを別のインターフェースに適合させるためのデザインパターンです。異なるインターフェースを持つクラスを統一的に扱えるようにすることで、既存のコードを変更せずに新しい機能を追加できます。
デコレータパターン (Decorator Pattern)
デコレータパターンは、オブジェクトに対して動的に新しい機能を追加するためのデザインパターンです。このパターンを使用することで、継承を使わずにオブジェクトの振る舞いを変更することができます。デコレータは、元のオブジェクトと同じインターフェースを実装し、元のオブジェクトのメソッドをラップします。
各言語でのサンプルコード
Python
アダプタパターン
class JapaneseSpeaker:
def hello(self):
return "こんにちは"
class EnglishSpeaker:
def greet(self):
return "Hello"
class EnglishAdapter:
def __init__(self, english_speaker):
self.english_speaker = english_speaker
def hello(self):
return self.english_speaker.greet()
# 使用例
japanese = JapaneseSpeaker()
english = EnglishAdapter(EnglishSpeaker())
print(japanese.hello()) # こんにちは
print(english.hello()) # Hello
デコレータパターン
class Coffee:
def cost(self):
return 5
class MilkDecorator:
def __init__(self, coffee):
self.coffee = coffee
def cost(self):
return self.coffee.cost() + 2
class SugarDecorator:
def __init__(self, coffee):
self.coffee = coffee
def cost(self):
return self.coffee.cost() + 1
# 使用例
coffee = Coffee()
milk_coffee = MilkDecorator(coffee)
sugar_milk_coffee = SugarDecorator(milk_coffee)
print(sugar_milk_coffee.cost()) # 8
C#
アダプタパターン
public class JapaneseSpeaker {
public string Hello() {
return "こんにちは";
}
}
public class EnglishSpeaker {
public string Greet() {
return "Hello";
}
}
public class EnglishAdapter : JapaneseSpeaker {
private EnglishSpeaker englishSpeaker;
public EnglishAdapter(EnglishSpeaker speaker) {
this.englishSpeaker = speaker;
}
public new string Hello() {
return englishSpeaker.Greet();
}
}
// 使用例
JapaneseSpeaker japanese = new JapaneseSpeaker();
EnglishAdapter english = new EnglishAdapter(new EnglishSpeaker());
Console.WriteLine(japanese.Hello()); // こんにちは
Console.WriteLine(english.Hello()); // Hello
デコレータパターン
public class Coffee {
public virtual int Cost() {
return 5;
}
}
public class MilkDecorator : Coffee {
private Coffee coffee;
public MilkDecorator(Coffee coffee) {
this.coffee = coffee;
}
public override int Cost() {
return coffee.Cost() + 2;
}
}
public class SugarDecorator : Coffee {
private Coffee coffee;
public SugarDecorator(Coffee coffee) {
this.coffee = coffee;
}
public override int Cost() {
return coffee.Cost() + 1;
}
}
// 使用例
Coffee coffee = new Coffee();
Coffee milkCoffee = new MilkDecorator(coffee);
Coffee sugarMilkCoffee = new SugarDecorator(milkCoffee);
Console.WriteLine(sugarMilkCoffee.Cost()); // 8
C++
アダプタパターン
#include <iostream>
#include <string>
class JapaneseSpeaker {
public:
std::string hello() {
return "こんにちは";
}
};
class EnglishSpeaker {
public:
std::string greet() {
return "Hello";
}
};
class EnglishAdapter : public JapaneseSpeaker {
EnglishSpeaker& englishSpeaker;
public:
EnglishAdapter(EnglishSpeaker& speaker) : englishSpeaker(speaker) {}
std::string hello() override {
return englishSpeaker.greet();
}
};
// 使用例
int main() {
JapaneseSpeaker japanese;
EnglishSpeaker english;
EnglishAdapter adaptedEnglish(english);
std::cout << japanese.hello() << std::endl; // こんにちは
std::cout << adaptedEnglish.hello() << std::endl; // Hello
return 0;
}
デコレータパターン
#include <iostream>
class Coffee {
public:
virtual int cost() {
return 5;
}
};
class MilkDecorator : public Coffee {
Coffee& coffee;
public:
MilkDecorator(Coffee& c) : coffee(c) {}
int cost() override {
return coffee.cost() + 2;
}
};
class SugarDecorator : public Coffee {
Coffee& coffee;
public:
SugarDecorator(Coffee& c) : coffee(c) {}
int cost() override {
return coffee.cost() + 1;
}
};
// 使用例
int main() {
Coffee coffee;
MilkDecorator milkCoffee(coffee);
SugarDecorator sugarMilkCoffee(milkCoffee);
std::cout << sugarMilkCoffee.cost() << std::endl; // 8
return 0;
}
Java
アダプタパターン
class JapaneseSpeaker {
public String hello() {
return "こんにちは";
}
}
class EnglishSpeaker {
public String greet() {
return "Hello";
}
}
class EnglishAdapter extends JapaneseSpeaker {
private EnglishSpeaker englishSpeaker;
public EnglishAdapter(EnglishSpeaker speaker) {
this.englishSpeaker = speaker;
}
@Override
public String hello() {
return englishSpeaker.greet();
}
}
// 使用例
public class Main {
public static void main(String[] args) {
JapaneseSpeaker japanese = new JapaneseSpeaker();
EnglishAdapter english = new EnglishAdapter(new EnglishSpeaker());
System.out.println(japanese.hello()); // こんにちは
System.out.println(english.hello()); // Hello
}
}
デコレータパターン
class Coffee {
public int cost() {
return 5;
}
}
class MilkDecorator extends Coffee {
private Coffee coffee;
public MilkDecorator(Coffee coffee) {
this.coffee = coffee;
}
@Override
public int cost() {
return coffee.cost() + 2;
}
}
class SugarDecorator extends Coffee {
private Coffee coffee;
public SugarDecorator(Coffee coffee) {
this.coffee = coffee;
}
@Override
public int cost() {
return coffee.cost() + 1;
}
}
// 使用例
public class Main {
public static void main(String[] args) {
Coffee coffee = new Coffee();
Coffee milkCoffee = new MilkDecorator(coffee);
Coffee sugarMilkCoffee = new SugarDecorator(milkCoffee);
System.out.println(sugarMilkCoffee.cost()); // 8
}
}
JavaScript
アダプタパターン
class JapaneseSpeaker {
hello() {
return "こんにちは";
}
}
class EnglishSpeaker {
greet() {
return "Hello";
}
}
class EnglishAdapter {
constructor(englishSpeaker) {
this.englishSpeaker = englishSpeaker;
}
hello() {
return this.englishSpeaker.greet();
}
}
// 使用例
const japanese = new JapaneseSpeaker();
const english = new EnglishAdapter(new EnglishSpeaker());
console.log(japanese.hello()); // こんにちは
console.log(english.hello()); // Hello
デコレータパターン
class Coffee {
cost() {
return 5;
}
}
class MilkDecorator {
constructor(coffee) {
this.coffee = coffee;
}
cost() {
return this.coffee.cost() + 2;
}
}
class SugarDecorator {
constructor(coffee) {
this.coffee = coffee;
}
cost() {
return this.coffee.cost() + 1;
}
}
// 使用例
const coffee = new Coffee();
const milkCoffee = new MilkDecorator(coffee);
const sugarMilkCoffee = new SugarDecorator(milkCoffee);
console.log(sugarMilkCoffee.cost()); // 8
各言語の解説
言語 | アダプタパターンの実装方法 | デコレータパターンの実装方法 | 特徴 |
---|---|---|---|
Python | インターフェース適合のためのクラスラップ | オブジェクトに動的に機能を追加するクラスラップ | シンプルで柔軟、直感的に使いやすい |
C# | インターフェースの継承とメソッドのオーバーライド | 継承を利用したクラスラップ | 強力な型安全性とエラーチェックが可能 |
C++ | 継承とポインタを使用したクラスラップ | 仮想メソッドを使用してオブジェクトをラップする | 高速で効率的、特に低レベルプログラムで有効 |
Java | インターフェースの継承とメソッドのオーバーライド | 継承を利用したクラスラップ | 強力なオブジェクト指向機能と堅牢性 |
JavaScript | クラスやオブジェクトのラップ | オブジェクトやクラスに動的に機能を追加する関数 | 柔軟でシンプル、フロントエンドやNode.js環境に最適 |
まとめ
アダプタパターンは、異なるインターフェースを持つクラスを統一的に扱うために使用され、既存のコードを変更せずに新しい機能を追加するのに役立ちます。一方、デコレータパターンは、オブジェクトに動的に機能を追加するのに適しており、継承を使わずに柔軟な機能拡張が可能です。次回は「ファクトリーパターンと抽象ファクトリーパターン」について学習しましょう。
コメント