LoginSignup
1
1

More than 1 year has passed since last update.

Abstract Factoryパターン 例(サカつくの場合)

Last updated at Posted at 2022-12-10

背景

デザインパターンの本を読んで、わかったつもりになっていても、いざ使おうとしたときに使えない。
いたずらにパターンを適用しようとしても逆効果になるかもしれない。
使いこなすためには、どんなときにパターンを適用すれば良いか理解したうえで、応用できないといけない。
なので、使えそうなときはどんなときか身近な例を考えて作ってみました。

参考資料

Abstract Factory 解釈

  • 直訳では「抽象的な工場」ですが、いろんな部品を組み合わせて一つの製品を作るときに有効なパターンで、部品は固定であるときが有効
  • 逆にいちいち部品が変わる場合は使わない方が良い

僕の身の回りでどんなケースがあるか考えたときに、
サッカーは11人でやるもので監督が戦術を決めて、選手がプレーすることは変わらない、というのを題材にしてみようと思いました。

クラス

無題のマップ.png

サッカーチームファクトリーがAbstract Factoryクラス、
FW、監督クラスは抽象部品クラスです。
サンフレファクトリークラス、日本代表クラスが具体的なファクトリークラス
ピエロス・ソティリウ、堂安、スキッベ、森保が具体的な部品クラスです。

今年のサンフレッチェは、なんといっても2022年度最優秀監督賞を取ったスキッベ監督ですよね。
FWのピエロスですが、今年はルヴァン杯での決勝戦でヒーローになりましたが、来年はリーグ戦での活躍を期待してます。

※クラス図はGitMindで作成

実装(抽象クラス)

Abstract.h
#pragma once

/* Abstract */
class abstract_FW{
    public:
        virtual void shoot() = 0;
        virtual ~abstract_FW(){}
};

/* Abstract */
class abstract_Manager{
    public:
        virtual void tactics() = 0;
        virtual ~abstract_Manager(){}
};

/* Abstract */
class soccerteam_Abstractfactory{
    public:
        virtual abstract_FW *CreatePlayer() = 0;
        virtual abstract_Manager *CreateManager() = 0;
        virtual ~soccerteam_Abstractfactory(){};
};


実装(具象クラス)

Sanfrecce.h
#pragma once

/* Concrete */
class PIEROS_SOTIRIOU : public abstract_FW{
    public:
        void shoot();
        ~PIEROS_SOTIRIOU(){}
};

/* Concrete */
class Skibbe : public abstract_Manager{
    public:
        void tactics();
        ~Skibbe(){}
};

/* Concrete */
class Sanfrecce : public soccerteam_Abstractfactory{
    public:
        abstract_FW *CreatePlayer();
        abstract_Manager *CreateManager();
        ~Sanfrecce(){}
};


Sanfrecce.cpp
#include <iostream>
#include "Abstract.h"
#include "Sanfrecce.h"

/* Concrete */
void PIEROS_SOTIRIOU::shoot(){
    std::cout << "PIEROS_SOTIRIOU:shoot\r\n";
}

/* Concrete */
void Skibbe::tactics(){
    std::cout << "Skibbe:3-6-1\r\n";
}

/* Concrete */
abstract_Manager *Sanfrecce::CreateManager(){
    return new Skibbe();
}

abstract_FW *Sanfrecce::CreatePlayer(){
    return new PIEROS_SOTIRIOU();
}
Japan.h
#pragma once

/* Concrete */
class Doan : public abstract_FW{
    public:
        void shoot();
        ~Doan(){}
};

/* Concrete */
class Moriyasu : public abstract_Manager{
    public:
        void tactics();
        ~Moriyasu(){}
};

/* Concrete */
class Japan : public soccerteam_Abstractfactory{
    public:
        abstract_FW *CreatePlayer();
        abstract_Manager *CreateManager();
        ~Japan(){}
};
Japan.cpp
#include <iostream>
#include "Abstract.h"
#include "Japan.h"

/* Concrete */
void Doan::shoot(){
    std::cout << "Doan:shoot\r\n";
}

/* Concrete */
void Moriyasu::tactics(){
    std::cout << "Moriyasu:5-4-1\r\n";
}

/* Concrete */
abstract_Manager *Japan::CreateManager(){
    return new Moriyasu();
}

abstract_FW *Japan::CreatePlayer(){
    return new Doan();
}

main.cpp

#include <iostream>
#include "Abstract.h"
#include "Sanfrecce.h"
#include "Japan.h"

int main()
{
    int team;
    soccerteam_Abstractfactory *factory;

    std::cout << "Enter team(0:sanfrecce, 1:Japan)";
    std::cin >> team;
 
    switch(team){
        case 0:
            factory = new Sanfrecce();
            break;
        case 1:
            factory = new Japan();
            break;
    }   

    /* ここからは変わらない、具象クラスは意識していない */

    if (factory != NULL){
    abstract_FW * fw = factory->CreatePlayer();
    abstract_Manager * mg = factory->CreateManager();
    
    mg->tactics();
    fw->shoot();
    delete fw;
    delete factory;
    }else{
        std::cerr << "error";
    }

    return 0;
}

実行結果

% g++ -o AbstractFactory Sanfrecce.cpp main.cpp Japan.cpp
% ./AbstractFactory 
Enter team(0:sanfrecce, 1:Japan)0
Skibbe:3-6-1
PIEROS_SOTIRIOU:shoot

% ./AbstractFactory
Enter team(0:sanfrecce, 1:Japan)1
Moriyasu:5-4-1
Doan:shoot

サンフレッチェの場合は、スキッベ監督の戦術3-6-1と、ピエロスがシュートする、という結果が表示されます。
日本代表の場合は、森保監督の戦術5-4-1と、堂安がシュートする、という結果が表示されます。

総括

今回のキモとなる部分は、
抽象クラスであるsoccerteam_Abstractfactory型でインスタンスを生成後は、
具体的なクラスを意識せずに、監督の戦術と、FWのシュートというメソッドが呼び出せていることにあります。

このように、たとえば他のJリーグのチームに置き換えても同じ部品(プレイヤーと監督)であることは変わらないので、今回のデザインパターンが有効であると思いました。

他のデザインパターンでも例を考えて作ってみたいと思います。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1