「こんにちは、アミーゴ!」
「こんにちは、ビラーボ!」
「今日の私たちのトピックは単に興味深いだけではなく、まさに壮大なものになるでしょう。」
「今日はデザインパターンとは何かについて説明します。 」
「すごいですね!彼らのことはよく聞いています。待ちきれません!」
「経験豊富なプログラマは、多くのクラスを作成しなければなりません。しかし、この仕事で最も難しいのは、どのクラスを作成するか、そしてクラス間で作業をどのように分割するかを決定することです。」
「そのような問題を解決すればするほど、いくつかの解決策は良いが、他の解決策は悪いということが分かるようになりました。」
「悪いソリューションは通常、解決するよりも多くの問題を引き起こします。拡張が不十分で、多くの不必要な制限が生じるなどです。そして、良いソリューションはその逆です。」
「何か例えることはありますか?」
「あなたが家を建てているとしましょう。そして、それが何でできているのかを考えています。壁、床、天井が必要だと決めます。その結果、陸屋根の家を建てます。 「そのような家はひび割れ、屋根から雨漏りが発生します。これは悪い解決策です。」
「逆に、基礎、壁、切妻屋根で構成される家は良い解決策でしょう。雪が屋根から滑り落ちるので、大雪でも問題ありません。また、基礎がしっかりしているので、土壌の移動は心配する必要はありません。」安定性。このようなソリューションを良いソリューションと呼びます。」
「なるほど。ありがとう。」
「わかりました。それでは続けます。」
「やがて、良い解決策はデザインパターンとして知られるようになり、悪い解決策はアンチパターンと呼ばれるようになりました。」
「デザイン パターンは質問に対する答えのようなものです。その質問を聞いたことがない場合、理解するのは困難です。」
「パターンの最初のカテゴリは創造パターンです。このようなパターンは、オブジェクトの作成に関連する優れたソリューションを説明します。」
「オブジェクトを作成するのは何がそんなに難しいのですか?」
「たまたまですが、まさにそれが私たちがこれから探求しようとしているものです。」
シングルトンパターン。

「多くの場合、プログラムでは、一部のオブジェクトのコピーが 1 つしか存在できません。たとえば、コンソール、ロガー、ガベージ コレクターなどです。」
「悪い解決策:オブジェクトを作成せず、メソッドがすべて静的であるクラスを作成するだけです。」
"良い解決策: 単一のオブジェクトを作成し、それを静的変数に保存します。クラスの 2 番目のオブジェクトが作成されないようにします。例:"
class Sun
{
private static Sun instance;
public static Sun getInstance()
{
if (instance == null)
instance = new Sun();
return instance;
}
private Sun()
{
}
}
Sun sun = Sun.getInstance();
"それは簡単です。"
「まず、コンストラクターをプライベートにします。これで、コンストラクターはクラス内からのみ呼び出すことができます。Sun クラスのメソッド内を除くすべての場所で Sun オブジェクトの作成をブロックしました。」
「第 2 に、このクラスのオブジェクトは getInstance() メソッドを呼び出すことによってのみ取得できます。これは Sun オブジェクトを作成できる唯一のメソッドであるだけでなく、そのようなオブジェクトが 1 つだけ存在することも保証します。」
"そうか。"
「『さて、具体的にはどうすればよいだろうか?』と考えたとき、パターンは『これを試してみてください。これは最良の解決策の 1 つです』と言うのです。」
「ありがとう。今、状況が明らかになり始めています。」
「このパターンについては、 ここでも読むことができます。」
工場のパターン。

「これはプログラマがよく直面する状況です。いくつかの基本クラスと多数のサブクラスがあります。たとえば、ゲーム キャラクター クラス (Gameperson) と、それを継承する他のすべてのキャラクターのクラスです。」
「次のクラスがあるとします。」
abstract class GamePerson
{
}
class Warrior extends GamePerson
{
}
class Mag extends GamePerson
{
}
class Troll extends GamePerson
{
}
class Elf extends GamePerson
{
}
「問題は、これらのクラスのオブジェクトの作成をどのように柔軟かつ便利に管理できるかということです。」
「この問題が現実離れしていると思われる場合は、ゲーム内で何十もの剣と盾、何百もの魔法の呪文、そして何千ものモンスターを作成する必要があることを想像してください。ここでは、オブジェクト作成のための便利なアプローチなしでは済まされません。 」
「Factoryパターンは良い解決策を提供します。」
「まず、値がさまざまなクラスに対応する列挙型を作成する必要があります。」
「2 番目に、列挙値に基づいてオブジェクトを作成する静的メソッドを持つ特別なFactoryクラスを作成します。」
"例えば:"
public enum PersonType
{
UNKNOWN,
WARRIOR,
MAG,
TROLL,
ELF,
}
public class PersonFactory
{
public static GamePerson createPerson(PersonType personType)
{
switch(personType)
{
WARRIOR:
return new Warrior();
MAG:
return new Mag();
TROLL:
return new Troll();
ELF:
return new Elf();
default:
throw new GameException();
}
}
}
GamePerson person = PersonFactory.createPerson(PersonType.MAG);
「つまり、オブジェクトの作成を管理するための特別なクラスを作成したということですか?」
「はい。」
「それで、これにはどのようなメリットがあるのでしょうか?」
「まず、このクラスでは、オブジェクトを必要なデータで初期化できます。」
「第 2 に、最終的に目的のオブジェクトを作成するために、メソッド間で必要な列挙値を好きなだけ渡すことができます。」
「第三に、列挙フィールドの数はクラスの数と一致する必要はありません。文字の種類は多くても、クラスの数はほとんどありません。」
「たとえば、Mag & Warrior は1 つのクラス (Human) を使用しますが、異なる強さと魔法のプロパティ (コンストラクターの引数) を持ちます。」
「これは次のようになります (わかりやすくするために、ダークエルフも追加しました):」
public enum PersonType
{
UNKNOWN,
WARRIOR,
MAG,
TROLL,
ELF,
DARK_ELF
}
public class PersonFactory
{
public static GamePerson createPerson(PersonType personType)
{
switch(personType)
{
WARRIOR:
return new Human(10, 0); // Strength, magic
MAG:
return new Human(0, 10); // Strength, magic
TROLL:
OGR:
return new Troll();
ELF:
return new Elf(true); // true – good, false – evil
DARK_ELF:
return new Elf(false); // true – good, false – evil
default:
throw new GameException();
}
}
}
GamePerson person = PersonFactory.createPerson(PersonType.MAG);
「上の例では、6 つの異なるタイプのオブジェクトを作成するために 3 つのクラスだけを使用しました。これは非常に便利です。さらに、これらすべてのロジックが 1 つのクラスと 1 つのメソッドに集中しています。」
「ここで、Ogre 用に別のクラスを作成することにしたとします。ここでは、アプリケーションの半分ではなく、数行のコードを変更するだけです。」
「同意します。それは良い解決策です。」
「そして、それが私が話していることです。デザインパターンは優れたソリューションのコレクションです。」
「私も、どこで使えるのか知りたいのですが…」
「はい。同意します。すぐには理解できないでしょう。それでも、知らないままできないよりは、知っていてもできない方が良いです。このパターンに関する別の役立つリンクがあります: Factory Pattern」
"ああ、ありがとう。"
「抽象的な工場パターン」
「多くのオブジェクトがある場合、工場のための工場を作成するというアイデアが思い浮かぶことがあります。このような工場は、抽象ファクトリーと呼ばれます。」
「これはどこに必要ですか?!」
「同一のオブジェクトのグループがいくつかあるとします。これは、例で示す方が簡単です。」
「ゲーム内に人間、エルフ、デーモンの 3 つの種族があるとします。バランスをとるために、各種族には戦士、射手、魔術師がいます。プレイヤーは自分がプレイしている種族に属するオブジェクトのみを作成できます」ゲームでは次のようになります。コードでは次のようになります。」
class Warrior
{
}
class Archer
{
}
class Mag
{
}
class HumanWarrior extends Warrior
{
}
class HumanArcher extends Archer
{
}
class HumanMag extends Mag
{
}
class ElfWarrior extends Warrior
{
}
class ElfArcher extends Archer
{
}
class ElfMag extends Mag
{
}
class DaemonWarrior extends Warrior
{
}
class DaemonArcher extends Archer
{
}
class DaemonMag extends Mag
{
}
それでは、種族、あるいは軍隊と呼んでもいいものを作りましょう。
abstract class Army
{
public Warrior createWarrior();
public Archer createArcher();
public Mag createMag();
}
class HumanArmy extends Army
{
public Warrior createWarrior()
{
return new HumanWarrior();
}
public Archer createArcher()
{
return new HumanArcher();
}
public Mag createMag()
{
return new HumanMag();
}
}
class ElfArmy extends Army
{
public Warrior createWarrior()
{
return new ElfWarrior();
}
public Archer createArcher()
{
return new ElfArcher();
}
public Mag createMag()
{
return new ElfMag();
}
}
class DaemonArmy extends Army
{
public Warrior createWarrior()
{
return new DaemonWarrior();
}
public Archer createArcher()
{
return new DaemonArcher();
}
public Mag createMag()
{
return new DaemonMag();
}
}
「でも、これどうやって使うの?」
「プログラムのどこでも Army、Warrior、Archer、Mage クラスを使用して、必要なオブジェクトを作成できます。目的の Army サブクラスのオブジェクトを渡すだけです。」
"例えば:"
Army humans = new HumanArmy();
Army daemons = new DaemonArmy();
Army winner = FightSimulator.simulate(humans, daemons);
「上の例では、異なる種族 (軍隊) 間の戦闘をシミュレートするクラスがあります。必要なのは 2 つの Army オブジェクトを渡すだけです。クラス自体はそれらを使用してさまざまな軍隊を作成し、勝者を特定するためにそれらの間で仮想戦闘を実行します。 。」
「なるほど。ありがとうございます。実に興味深いアプローチですね。」
「あなたが何と言おうと、良い解決策です。」
「はい。」
「このトピックに関する別の優れたリンクは次のとおりです: 抽象ファクトリー パターン」
GO TO FULL VERSION