[Design pattern] 1-3. ファクトリーメソッドパターン(Factory method pattern)
こんにちは。明月です。
この投稿はデザインパターンのファクトリーメソッドパターン(Factory method pattern)に関する説明です。
以前の投稿でビルダーパターンに関して説明しました。
link - [Design pattern] 1-2. ビルダーパターン(Builder pattern)
ビルダーパターンは簡単に説明するとBuilderクラスとDirectorクラスの組み合いで一つのインスタンスを生成する生成パターンです。このファクトリーメソッドパターンもビルダーパターンと同じ生成パターンの一つで、インスタンスを生成するパターンです。
このファクトリーメソッドパターンはメソッドのパラメータにより生成されるインスタンスを変わる形のパターンです。
#pragma once
#include <stdio.h>
#include <iostream>
using namespace std;
// 抽象クラス
class INode {
public:
// 抽象メソッド
virtual void print() = 0;
};
// Node1クラス、INodeクラスを継承する。
class Node1 : public INode {
public:
// 出力関数
virtual void print() {
// コンソール出力
cout << "Node1 Class " << endl;
}
};
// Node2クラス、INodeクラスを継承する。
class Node2 : public INode {
public:
// 出力関数
virtual void print() {
// コンソール出力
cout << "Node2 Class " << endl;
}
};
// ファクトリーメソッドパターンの関数
INode* factory(int type) {
// パラメータのtypeの値が0の場合
if (type == 0) {
// Node1インスタンスを生成
return new Node1();
}
// パラメータのtypeの値が1の場合
else if (type == 1) {
// Node2インスタンスを生成
return new Node2();
}
// nullリターン
return nullptr;
}
// 実行関数
int main() {
// ファクトリーメソッドのパラメータで0を入れたら
INode* node = factory(0);
// Node1クラスのprint関数が実行
node->print();
// メモリ解除
delete node;
// ファクトリーメソッドのパラメータで1を入れたら
node = factory(1);
// Node2クラスのprint関数が実行
node->print();
// メモリ解除
delete node;
return 0;
}
上の例をみればfactory関数のパラメータの値によりNode1クラスのインスタンスを生成するかNode2クラスのインスタンスを生成することが決めます。
ビルダーパターンと比べたらすごく簡単な構造です。
// 実行関数があるクラス
public class Program {
// ファクトリーメソッドパターンの関数
public static INode factory(String type) {
// パラメータのtypeが大小文字に関係せず、NODE1の場合
if ("NODE1".equalsIgnoreCase(type)) {
// Node1インスタンスを生成
return new Node1();
// パラメータのtypeが大小文字に関係せず、NODE2の場合
} else if ("NODE2".equalsIgnoreCase(type)) {
// Node2インスタンスを生成
return new Node2();
}
// 上の条件に合うことがなければnullをリターン
return null;
}
// 実行関数
public static void main(String... args) {
// ファクトリーメソッドにnode1の値を入れたら
INode node = factory("node1");
// Node1インスタンスが生成され、コンソール出力
node.print();
// ファクトリーメソッドにnode2の値を入れたら
node = factory("node2");
// Node2インスタンスが生成され、コンソール出力
node.print();
}
}
// インターフェース
interface INode {
// コンソール出力の抽象メソッド
void print();
}
// Node1クラス、INodeインスタンスを継承する。
class Node1 implements INode {
// 再定義
@Override
public void print() {
// コンソール出力
System.out.println("Node 1 class");
}
}
// Node2クラス、INodeインスタンスを継承する。
class Node2 implements INode {
// 再定義
@Override
public void print() {
// コンソール出力
System.out.println("Node 2 class");
}
}
Javaの例ではパラメータの値をStringで受けます。つまり、Stringデータによりインスタンスを生成することができます。
こんなことになると実際のプロジェクトにはデータベースやユーザから受ける値により生成するインスタンスを変わって実行するロジックを選択することができます。
そしてファクトリーメソッドにはリターンするタイプを一つ種類のタイプに統一しなければならないのでinterfaceを使いました。
using System;
namespace Example
{
// インターフェース
interface INode
{
// コンソール出力の抽象メソッド
void Print();
}
// Node1クラス、INodeインスタンスを継承する。
class Node1 : INode
{
// 再定義関数
public void Print()
{
// コンソール出力
Console.WriteLine("Node1 Class");
}
}
// Node2クラス、INodeインスタンスを継承する。
class Node2 : INode
{
// 再定義関数
public void Print()
{
// コンソール出力
Console.WriteLine("Node2 Class");
}
}
// 列挙型
enum NodeType
{
Node1,
Node2
}
// 実行関数があるクラス
class Program
{
// ファクトリーメソッドパターンの関数
static INode Factory(NodeType type)
{
// typeの値がNodeType.Node1なら
if (type == NodeType.Node1)
{
// Node1クラスのインスタンスを生成
return new Node1();
}
// typeの値がNodeType.Node2なら
else if (type == NodeType.Node2)
{
// Node2クラスのインスタンスを生成
return new Node2();
}
// 上の条件に合うことがなければnullをリターン
return null;
}
// 実行関数
static void Main(string[] args)
{
// ファクトリーメソッドにNodeType.Node1の値を入れたら
INode node = Factory(NodeType.Node1);
// Node1インスタンスが生成され、コンソール出力
node.Print();
// ファクトリーメソッドにNodeType.Node2の値を入れたら
node = Factory(NodeType.Node2);
// Node1インスタンスが生成され、コンソール出力
node.Print();
Console.WriteLine("Press any key...");
Console.ReadKey();
}
}
}
上の例はStringタイプではなく、列挙型の値によりインスタンスを生成しました。
Stringタイプを使うことはもし、String値にタイプミスがある場合、デバッグ段階でエラーをチェックしないので、バグが発生する可能性があります。でも、列挙型でパラメータを設定すればバグが発生する可能性は少しなくすことができます。
ファクトリーメソッドパターンは普通はシングルトンパターンと組み合いしてよく使います。なので、EntityタイプのデータクラスよりControllerみたいに処理クラスによく使います。
using System;
namespace Example
{
// インターフェース
interface INode
{
// コンソール出力の抽象メソッド
void Print();
}
// Node1クラス、INodeインスタンスを継承する。
class Node1 : INode
{
// シングルトンパターンのための変数
private static Node1 singleton = null;
// コンストラクタはprivate
private Node1() { }
// インスタンスを取得関数
public static Node1 GetInstance()
{
// インスタンスがない場合
if(singleton == null)
{
// インスタンス生成
singleton = new Node1();
}
// インスタンスリターン
return singleton;
}
// 再定義関数
public void Print()
{
// コンソール出力
Console.WriteLine("Node1 Class");
}
}
// Node2クラス、INodeインスタンスを継承する。
class Node2 : INode
{
// シングルトンパターンのための変数
private static Node2 singleton = null;
// コンストラクタはprivate
private Node2() { }
// インスタンスを取得関数
public static Node2 GetInstance()
{
// インスタンスがない場合
if (singleton == null)
{
// インスタンス生成
singleton = new Node2();
}
// インスタンスリターン
return singleton;
}
// 再定義関数
public void Print()
{
// コンソール出力
Console.WriteLine("Node2 Class");
}
}
// 列挙型
enum NodeType
{
Node1,
Node2
}
// 実行関数があるクラス
class Program
{
// ファクトリーメソッドパターンの関数
static INode Factory(NodeType type)
{
// typeの値がNodeType.Node1なら
if (type == NodeType.Node1)
{
// Node1クラスのインスタンスを生成
return new Node1();
}
// typeの値がNodeType.Node2なら
else if (type == NodeType.Node2)
{
// Node2クラスのインスタンスを生成
return new Node2();
}
// 上の条件に合うことがなければnullをリターン
return null;
}
// 実行関数
static void Main(string[] args)
{
// ファクトリーメソッドにNodeType.Node1の値を入れたら
INode node = Factory(NodeType.Node1);
// Node1インスタンスが生成され、コンソール出力
node.Print();
// ファクトリーメソッドにNodeType.Node2の値を入れたら
node = Factory(NodeType.Node2);
// Node1インスタンスが生成され、コンソール出力
node.Print();
Console.WriteLine("Press any key...");
Console.ReadKey();
}
}
}
上の例はNode1クラスとNode2クラスにあるコンストラクタをprivateに設定してGetInstance関数でインスタンスを取得する形のシングルトンパターンを作成しました。
ファクトリーメソッドにはパラメータにより各クラスのGetInstance関数を呼び出し、インスタンスをリターンします。
この構造を何処でよく見えるかと思えばウェブのMVCの形のControllerクラスでウェブのURL要請により呼び出すクラスインスタンスが変わることと同じ構造だと思います。(Routeクラス)
ここまでデザインパターンのファクトリーメソッドパターン(Factory method pattern)に関する説明でした。
ご不明なところや間違いところがあればコメントしてください。
- [Design pattern] 3-2. 責任の連鎖パターン(Chain of responsibility pattern)2021/11/04 19:27:58
- [Design pattern] 3-1. ストラテジーパターン(Strategy pattern)2021/11/03 18:38:52
- [Design pattern] 2-7. ファサードパターン(Facade pattern)2021/11/02 19:32:31
- [Design pattern] 2-6. プロキシパターン(Proxy pattern)2021/11/01 19:42:44
- [Design pattern] 2-5. フライウェイトパターン(Flyweight pattern)2021/10/29 19:48:27
- [Design pattern] 2-4. デコレーターパターン(Decorator pattern)2021/10/28 20:11:13
- [Design pattern] 2-3. ブリッジパターン(Bridge pattern)2021/10/27 20:32:21
- [Design pattern] 2-2. コンポジットパターン(Composite pattern)2021/10/27 20:30:54
- [Design pattern] 2-1. アダプターパターン(Adapter pattern)2021/10/26 19:12:40
- [Design pattern] 1-5. プロトタイプパターン(Prototype pattern)2021/10/22 19:35:45
- [Design pattern] 1-4. デザインパターンの抽象ファクトリーパターン(Abstract factory pattern)2021/10/15 19:31:03
- [Design pattern] 1-3. ファクトリーメソッドパターン(Factory method pattern)2021/06/23 19:45:37
- [Design pattern] 1-2. ビルダーパターン(Builder pattern)2021/06/11 19:06:28
- [Design pattern] 1-1. シングルトンパターン(Singleton pattern)2021/06/09 19:40:05
- [Design Pattern] デザインパターンの紹介2021/06/08 20:42:36
- check2024/04/10 19:03:53
- [Java] 64.Spring bootとReactを連結する方法(Buildする方法)2022/03/25 21:02:18
- [Javascript] Node.jsをインストールしてReactを使う方法2022/03/23 18:01:34
- [Java] 63. Spring bootでcronスケジューラとComponentアノテーション2022/03/16 18:57:30
- [Java] 62. Spring bootでWeb-Filterを設定する方法(Spring Security)2022/03/15 22:16:37
- [Java] JWT(Json Web Token)を発行、確認する方法2022/03/14 19:12:58
- [Java] 61. Spring bootでRedisデータベースを利用してセッションクラスタリング設定する方法2022/03/01 18:20:52
- [Java] 60. Spring bootでApacheの連結とロードバランシングを設定する方法2022/02/28 18:45:48
- [Java] 59. Spring bootのJPAでEntityManagerを使い方2022/02/25 18:27:48
- [Java] 58. EclipseでSpring bootのJPAを設定する方法2022/02/23 18:11:10
- [Java] 57. EclipseでSpring bootを設定する方法2022/02/22 19:04:49
- [Python] Redisデータベースに接続して使い方2022/02/21 18:23:49
- [Java] Redisデータベースを接続して使い方(Jedisライブラリ)2022/02/16 18:13:17
- [C#] Redisのデータベースを接続して使い方2022/02/15 18:46:09
- [CentOS] Redisデータベースをインストールする方法とコマンドを使い方2022/02/14 18:33:07