1. デザインパターンの概念と役割
設計パターンは、ソフトウェア設計における一般的な問題に対する一般的な解決策です。これらは、あるクラスの問題に対する経験の要約であり、過去の成功体験から要約されています。デザイン パターンを使用すると、ソフトウェア開発者はソフトウェア デザインの再利用性、保守性、拡張性、読みやすさを向上させながら、よくある間違いを回避できます。
デザインパターンは、創造パターン、構造パターン、行動パターンの3種類に分類できます。作成パターンには、シングルトン パターン、ファクトリ パターン、抽象ファクトリ パターン、ビルダー パターン、プロトタイプ パターンが含まれます。構造パターンには、アダプター パターン、ブリッジ パターン、デコレーター パターン、ファサード パターン、フライウェイト パターン、およびプロキシ パターンが含まれます。動作パターンには、テンプレート メソッド パターン、コマンド パターン、イテレータ パターン、オブザーバ パターン、メディエータ パターン、メメント パターン、インタプリタ パターン、および状態パターンが含まれます。
さまざまなデザインパターンがさまざまなシナリオに適しています。たとえば、Singleton パターンは、クラスのインスタンスが 1 つだけ存在することを確認する必要がある場合に適しており、Factory パターンは、一連の関連オブジェクトを作成する必要がある状況に適しており、Proxy パターンは、次のような状況に適しています。単一のオブジェクトへのアクセスを制御する必要があります。デザイン パターンは静的なものではなく、問題ごとに異なります。したがって、ソフトウェア開発者は、実際の状況に応じて適切な設計パターンを選択する必要があります。
2. 創作デザインパターンの概要と分類
創造デザイン パターンは、オブジェクトをより柔軟に作成し、オブジェクトを使用するコードから分離するために、オブジェクト作成の問題を解決することを目的としたオブジェクトの作成とインスタンス化のパターンです。創作パターンは以下の5種類に分類できます。
- シングルトン パターン: クラスにインスタンスが 1 つだけあることを保証し、そのインスタンスへのグローバル アクセス ポイントを提供します。
- ファクトリ パターン: オブジェクトを作成するためのインターフェイスを定義し、どのクラスをインスタンス化するかをサブクラスに決定させます。ファクトリ メソッドは、クラスのインスタンス化をそのサブクラスに延期します。
- Abstract Factory Pattern: 具体的なクラスを指定せずに、一連の関連オブジェクトまたは依存オブジェクトを作成するためのインターフェイスを提供します。
- ビルダー パターン: 複雑なオブジェクトの構築をその表現から分離し、同じ構築プロセスで異なる表現を作成できるようにします。
- プロトタイプ パターン: プロトタイプ インスタンスを使用して、作成するオブジェクトのタイプを指定し、これらのプロトタイプをコピーして新しいオブジェクトを作成します。
これらの設計パターンは実際のアプリケーションで広く使用されており、コードの再利用性、保守性、拡張性を向上させることができます。同時に、適用可能なシナリオや利点と欠点も異なるため、開発者は実際のアプリケーションで評価して選択する必要があります。
3. 単純なファクトリ パターン: ファクトリ メソッド パターンと抽象ファクトリ パターン
単純なファクトリ パターン、ファクトリ メソッド パターン、および抽象ファクトリ パターンはすべて創造的なデザイン パターンであり、その目的は、オブジェクトの作成を使用コードから分離し、コードのスケーラビリティと保守性を向上させることです。
シンプル ファクトリ パターン: 静的ファクトリ メソッド パターンとも呼ばれ、new キーワードを使用してオブジェクトを直接インスタンス化することなく、ファクトリ クラスを介してオブジェクトを作成します。このファクトリ クラスは、渡されたパラメータに基づいて作成されるオブジェクトのタイプを決定します。シンプル ファクトリ パターンはファクトリ クラスが 1 つしかないため、他の 2 つのパターンに比べて拡張性が劣ります。しかし、実装は簡単で、使用するのがより便利です。
// 创建产品接口
interface Product {
void show();
}
// 创建具体产品类
class ConcreteProduct1 implements Product {
@Override
public void show() {
System.out.println("具体产品1");
}
}
class ConcreteProduct2 implements Product {
@Override
public void show() {
System.out.println("具体产品2");
}
}
// 创建工厂类
class SimpleFactory {
public static Product createProduct(int type) {
switch (type) {
case 1:
return new ConcreteProduct1();
case 2:
return new ConcreteProduct2();
default:
return null;
}
}
}
// 测试类
public class SimpleFactoryDemo {
public static void main(String[] args) {
Product product1 = SimpleFactory.createProduct(1);
product1.show();
Product product2 = SimpleFactory.createProduct(2);
product2.show();
}
}
ファクトリ メソッド パターン: ポリモーフィック ファクトリ パターンとも呼ばれ、オブジェクトを作成するためのインターフェイスを定義しますが、どのクラスをインスタンス化するかをサブクラスに決定させます。このファクトリ メソッドは、クラスのインスタンス化をそのサブクラスに延期します。この利点は、新しい製品を追加する必要がある場合、既存のコードを変更せずに、特定の製品クラスと対応するファクトリ クラスを追加するだけで済み、オープン性とクロージャ性の原則に準拠していることです。
// 创建产品接口
interface Product {
void show();
}
// 创建具体产品类
class ConcreteProduct1 implements Product {
@Override
public void show() {
System.out.println("具体产品1");
}
}
class ConcreteProduct2 implements Product {
@Override
public void show() {
System.out.println("具体产品2");
}
}
// 创建工厂接口
interface Factory {
Product createProduct();
}
// 创建具体工厂类
class ConcreteFactory1 implements Factory {
@Override
public Product createProduct() {
return new ConcreteProduct1();
}
}
class ConcreteFactory2 implements Factory {
@Override
public Product createProduct() {
return new ConcreteProduct2();
}
}
// 测试类
public class FactoryMethodDemo {
public static void main(String[] args) {
Factory factory1 = new ConcreteFactory1();
Product product1 = factory1.createProduct();
product1.show();
Factory factory2 = new ConcreteFactory2();
Product product2 = factory2.createProduct();
product2.show();
}
}
抽象ファクトリ パターン: ツールボックス パターンとも呼ばれ、特定のクラスを指定せずに一連の関連オブジェクトまたは依存オブジェクトを作成するためのインターフェイスを提供します。抽象ファクトリ パターンは、特定のクラスを指定せずに、関連する製品クラスのセットをまとめて作成します。抽象ファクトリー パターンでは、製品ファミリーの製品をまとめて作成できるため、製品グループの一貫性が保証されます。ただし、ファクトリ メソッド パターンほど拡張性はありません。
// 创建产品接口
interface Product1 {
void show();
}
interface Product2 {
void show();
}
// 创建具体产品类
class ConcreteProduct1 implements Product1 {
@Override
public void show() {
System.out.println("具体产品1");
}
}
class ConcreteProduct2 implements Product2 {
@Override
public void show() {
System.out.println("具体产品2");
}
}
// 创建工厂接口
interface Factory {
Product1 createProduct1();
Product2 createProduct2();
}
// 创建具体工厂类
class ConcreteFactory1 implements Factory {
@Override
public Product1 createProduct1() {
return new ConcreteProduct1();
}
@Override
public Product2 createProduct2() {
return new ConcreteProduct2();
}
}
class ConcreteFactory2 implements Factory {
@Override
public Product1 createProduct1() {
return new ConcreteProduct1();
}
@Override
これらのファクトリーパターンは実際のアプリケーションで広く使用されています。シンプル ファクトリ パターンは単純なオブジェクト作成シナリオに適しており、ファクトリ メソッド パターンはより複雑な製品レベルのシナリオに適しており、抽象ファクトリ パターンは製品ファミリの作成に適しています。開発者は実際の状況に応じて選択して適用する必要があります。
4. ビルダーモード
ビルダー パターンは、複雑なオブジェクトの作成プロセスを複数の単純なステップに分割できる創造的なデザイン パターンで、コードがより明確になり、保守と拡張が容易になります。単純なファクトリ、ファクトリ メソッド、および抽象ファクトリとは異なり、ビルダー パターンは、オブジェクトの作成だけに焦点を当てるのではなく、オブジェクトを作成する複雑な構築プロセスに焦点を当てます。
ビルダー モードは次の役割に分類できます。
-
製品クラス (Product): 構築する必要があるオブジェクトを定義します。
-
抽象ビルダー クラス (Builder): 製品を構築するための複数の抽象メソッドを含む、製品を構築するための抽象インターフェイスを定義します。
-
Concrete Builder クラス (ConcreteBuilder): 特定の製品の構築プロセスを完了するための抽象ビルダー インターフェイスを実装します。
-
ディレクター: ビルダー インターフェイスを呼び出して、特定の順序で製品をビルドします。
// 创建产品类
class Product {
private String partA;
private String partB;
private String partC;
public String getPartA() {
return partA;
}
public void setPartA(String partA) {
this.partA = partA;
}
public String getPartB() {
return partB;
}
public void setPartB(String partB) {
this.partB = partB;
}
public String getPartC() {
return partC;
}
public void setPartC(String partC) {
this.partC = partC;
}
@Override
public String toString() {
return "Product{" +
"partA='" + partA + '\'' +
", partB='" + partB + '\'' +
", partC='" + partC + '\'' +
'}';
}
}
// 创建抽象建造者类
abstract class Builder {
public abstract void buildPartA();
public abstract void buildPartB();
public abstract void buildPartC();
public abstract Product getResult();
}
// 创建具体建造者类
class ConcreteBuilder extends Builder {
private Product product = new Product();
@Override
public void buildPartA() {
product.setPartA("PartA");
}
@Override
public void buildPartB() {
product.setPartB("PartB");
}
@Override
public void buildPartC() {
product.setPartC("PartC");
}
@Override
public Product getResult() {
return product;
}
}
// 创建指挥者类
class Director {
private Builder builder;
public Director(Builder builder) {
this.builder = builder;
}
public void construct() {
builder.buildPartA();
builder.buildPartB();
builder.buildPartC();
}
}
// 测试类
public class BuilderDemo {
public static void main(String[] args) {
Builder builder = new ConcreteBuilder();
Director director = new Director(builder);
director.construct();
Product product = builder.getResult();
System.out.println(product);
}
}
この例では、複数のコンポーネントを含む製品クラス (Product) を作成し、ビルダー パターンを使用してこの複雑なオブジェクトを作成します。まず、抽象ビルダー クラス (Builder) を定義します。これには、特定の構築プロセスを定義するための複数の抽象メソッドが含まれています。次に、抽象ビルダー インターフェイスを実装し、具象構築プロセスを完了する具象ビルダー クラス (ConcreteBuilder) を定義します。最後に、ビルダー インターフェイスを使用して具体的なプロダクトを作成し、特定の順序でビルダー インターフェイスのメソッドを呼び出す Director クラスを作成します。テスト クラスでは、具体的なビルダー オブジェクトを作成し、次にディレクター オブジェクトを使用してビルダー インターフェイスのメソッドを呼び出し、複数のコンポーネントを含む複雑なオブジェクトを作成します。
ビルダー パターンは、実際のプロジェクト、特に複雑なオブジェクトを作成する場合に広く使用されています。たとえば、Java では、StringBuilder クラスはビルダー パターンを使用して文字列オブジェクトを作成します。Spring フレームワークには、ビルダー パターンを適用する例も数多くあります。たとえば、XmlBeanDefinitionReader クラスは、ビルダー パターンを使用して BeanDefinition オブジェクトを作成します。
つまり、ビルダー パターンは、複雑なオブジェクトの作成プロセスを複数の単純なステップに分割するのに役立ち、コードがより明確になり、保守と拡張が容易になります。コード内で多数のコンストラクターやセッター メソッドを使用することを回避できるため、コードの可読性と保守性が向上します。
5. 試作パターン
プロトタイプ パターン (Prototype Pattern) は、再インスタンス化せずに既存のオブジェクトをコピーすることで新しいオブジェクトを作成できる創造的なデザイン パターンです。プロトタイプ モードは通常、複雑なオブジェクトの作成や作成プロセスに時間がかかる場合に適しています。既存のオブジェクトをコピーして新しいオブジェクトを作成すると、作成効率が向上し、同様のオブジェクトを繰り返し作成する問題を回避できます。
// 定义一个原型接口
public interface Prototype {
Prototype clone();
}
// 定义一个具体的原型类
public class ConcretePrototype implements Prototype {
private String name;
public ConcretePrototype(String name) {
this.name = name;
}
public Prototype clone() {
return new ConcretePrototype(name);
}
public String getName() {
return name;
}
}
// 定义一个客户端类
public class Client {
public static void main(String[] args) {
Prototype prototype = new ConcretePrototype("原型对象");
Prototype clone = prototype.clone();
System.out.println("原型对象的名称:" + prototype.getName());
System.out.println("克隆对象的名称:" + clone.getName());
}
}
上記のデモでは、まずプロトタイプ インターフェイス (Prototype) を定義しました。これには、現在のオブジェクトをコピーして新しいオブジェクトを作成するために使用されるクローン メソッド (clone) が含まれています。次に、特定のプロトタイプ クラス (ConcretePrototype) を定義します。これにより、プロトタイプ インターフェイスが実装され、特定のクローン作成プロセスが完了します。最後に、プロトタイプ オブジェクトの clone メソッドを呼び出して新しいオブジェクトを作成し、プロトタイプ オブジェクトとクローン オブジェクトの名前を出力するクライアント クラス (Client) を作成しました。
プロトタイプモードは実際のプロジェクトでも広く使われており、例えば Java では Object クラスがすべてのクラスのルートクラスとなり、既存のオブジェクトをコピーして新しいオブジェクトを作成する clone メソッドが提供されます。Springフレームワークでもプロトタイプパターンを適用した例は数多くあり、例えばBeanを作成する際、Springはまずプロトタイプオブジェクトを作成し、そのプロトタイプオブジェクトをコピーすることで類似したBeanオブジェクトを複数作成する。
つまり、プロトタイプ モードを使用すると、複雑なオブジェクトを迅速に作成できるため、コードの効率と保守性が向上します。同時に、コード内で同様のオブジェクトを繰り返し作成するという問題も回避され、メモリのオーバーヘッドが削減されます。
6. シングルトンモード
シングルトン パターン (シングルトン パターン) は、クラスにインスタンスが 1 つだけあることを保証し、この一意のインスタンスにアクセスするためのグローバル アクセス ポイントを提供する作成設計パターンです。
シングルトン モードを実装するにはさまざまな方法がありますが、以下では、より一般的に使用される 2 つの方法を紹介します。
空腹の中国のシングルトン パターン
ハングリー スタイルのシングルトン モードは最も単純な実装であり、クラスがロードされるときにシングルトン オブジェクトを作成するため、静的シングルトン モードとも呼ばれます。以下は、単純な空腹の中国のシングルトン パターンのサンプル コードです。
public class Singleton {
// 私有化构造函数,确保外部无法实例化该类
private Singleton() {
}
// 定义静态的单例对象
private static Singleton instance = new Singleton();
// 提供公共的访问方法,用于获取单例对象
public static Singleton getInstance() {
return instance;
}
}
上記のサンプル コードでは、クラスが外部でインスタンス化できないようにするためのプライベート コンストラクターを含むシングルトン クラスを定義します。次に、静的シングルトン オブジェクト インスタンスを定義し、クラスがロードされるときにこのオブジェクトを作成します。最後に、シングルトン オブジェクトを取得するためのパブリック アクセス メソッド getInstance を提供します。
遅延シングルトン パターン
public class Singleton {
// 私有化构造函数,确保外部无法实例化该类
private Singleton() {
}
// 定义静态的单例对象
private static Singleton instance;
// 提供公共的访问方法,用于获取单例对象
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
遅延シングルトン パターンは、getInstance メソッドが初めて呼び出されたときにシングルトン オブジェクトを作成する遅延読み込み実装です。単純な遅延シングルトン パターンのサンプル コードを次に示します。
public class Singleton {
// 私有化构造函数,确保外部无法实例化该类
private Singleton() {
}
// 定义静态的单例对象
private static Singleton instance;
// 提供公共的访问方法,用于获取单例对象
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
上記のサンプル コードでは、Singleton クラスも定義し、コンストラクターをプライベート化しました。違いは、クラスのロード時にシングルトン オブジェクトを作成するのではなく、getInstance メソッドで判断することで、インスタンスが null の場合は新しいシングルトン オブジェクトが作成され、それ以外の場合は既存のシングルトン オブジェクトが直接返されます。
シングルトン パターンは、実際のプロジェクトでも非常に広く使用されている設計パターンであり、たとえば Java では、Runtime クラスはシングルトン クラスであり、一意のインスタンスを取得するためのパブリック アクセス ポイントを提供します。Spring フレームワークには、シングルトン パターンを適用する例も多数あり、たとえば、BeanFactory はすべての Bean オブジェクトの管理を担当するシングルトン クラスです。
つまり、シングルトン パターンは、クラスのインスタンスが 1 つだけ存在することを保証し、コード内で同じオブジェクトを繰り返し作成する問題を回避するのに役立ちます。これにより、メモリのオーバーヘッドが削減され、コードの信頼性が向上します。