1 |ビルダーモードの概要
実世界であろうとソフトウェアシステムであろうと、車輪、ハンドル、エンジン、その他のコンポーネントを含む自動車など、複数のコンポーネント(パーツ)を持つ複雑なオブジェクトがいくつかあります。ほとんどのユーザーにとって、彼らはこれらの部品の組み立ての詳細を知らず、単一の部品を使用することはほとんどありませんが、完全な車を使用します。
思考:上記のシナリオに直面して、これらの部品を完全な車に組み立ててユーザーに返す方法。このシナリオは、ビルダーモードで解決する必要のある問題です。ビルダーモードでは、複数のコンポーネントを含む複雑なオブジェクトを段階的に作成する方法に焦点を当てて、パーツ自体をアセンブリプロセスから分離できます。ユーザーは、複雑なオブジェクトのタイプを指定するだけで、内部の詳細を知らなくてもオブジェクトを取得できます。ビルドの詳細。
ビルダーモードの定義
- ビルダーモード:複雑なオブジェクトの構築をその表現から分離して、同じ構築プロセスで異なる表現を作成できるようにします。
- ビルダーパターン:同じ構築プロセスで異なる表現を作成できるように、複雑なオブジェクトの構築をその表現から分離します。
ビルダーモードは、複数のパーツを含む複雑なオブジェクトの作成プロセスからクライアントを分離するオブジェクト作成モードです。クライアントは、複雑なオブジェクトの内部コンポーネントとアセンブリメソッドを知る必要はありませんが、必要なビルダーを知る必要があるだけです。入力するだけです。ビルダーモードは、複雑なオブジェクトを段階的に作成する方法に焦点を当てています。異なるビルダーは異なる作成プロセスを定義し、特定のビルダーは互いに独立しています。ビルダーの交換と追加は非常に便利であり、システムは優れたスケーラビリティを備えています。
2 |ビルダーパターンの構造と実現
2.1ビルダーモードの構造
- (1)Builder(abstract builder):Productオブジェクトを作成する各パーツの抽象インターフェースを指定します。通常、インターフェースでは2種類のメソッドが宣言されます。1種類のメソッドはBuildPartX()です(たとえば、図のBuildPartA)。 6-2()、BuildPartB()など)。これは、複雑なオブジェクトのさまざまな部分を作成するために使用されます。別のタイプのメソッドは、複雑なオブジェクトを返すために使用されるGetResult()です。Builderは、抽象クラスまたはインターフェースのいずれかです。
- (2)ConcreteBuilder(concrete builder):Builderインターフェースを実装し、各コンポーネントの特定の構築およびアセンブリメソッドを実現し、作成された複雑なオブジェクトを定義および明確化し、作成された複雑な製品オブジェクトを返すメソッド(メソッド抽象ビルダーで実装することもできます)。
- (3)製品(製品):複数の構成部品を含む、構築される複雑なオブジェクトであり、コンクリートビルダーは製品の内部表現を作成し、その組み立てプロセスを定義します。
- (4)ディレクター(ディレクター):ディレクターはディレクタークラスとも呼ばれ、複雑なオブジェクトの構築シーケンスを調整します。ディレクターと抽象ビルダーの間には関連付け関係があり、ビルダーはその中で呼び出すことができます。 Construct()構築メソッド複雑なオブジェクトの構築を完了するためのオブジェクトのコンポーネント構造とアセンブリメソッド。クライアントは通常、コマンダーと対話し、クライアント上の特定のビルダーのタイプを判別し、特定のビルダーオブジェクトを(構成ファイルとリフレクションメカニズムを介して)インスタンス化してから、コマンダークラスのコンストラクターまたはSetterメソッドを使用するだけで済みます。オブジェクトをコンダクタクラスに渡します。
2.2ビルダーモードの実装
複雑なオブジェクトは構築モードの定義で言及されていますが、複雑なオブジェクトとは何ですか?簡単に言うと、複雑なオブジェクトとは、複数のメンバー変数を含むオブジェクトを指し、これらのメンバーオブジェクトはコンポーネントまたはパーツとも呼ばれます。例えば:
- 自動車(複雑なオブジェクト)には、ステアリングホイール、ライト、エンジン、タイヤ、シート、その他のコンポーネントが含まれます。
- 電子メール(複雑なオブジェクト)には、送信者、受信者、件名、コンテンツ、添付ファイル、およびその他のコンポーネントが含まれます。
ビルダーモードのコード設計
using System;
namespace BuilderPattern
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello BuilderPattern!");
{
Builder builder = new ConcreteBuilder1();
Director director = new Director(builder);
Product product = director.Construct(); //构建复杂对象
Console.WriteLine($"【复杂对象】=> PartA:{product.PartA},PartB:{product.PartB},PartC:{product.PartC}");
}
}
}
#region BuilderPattern-Demo
/// <summary>
/// 产品
/// </summary>
class Product
{
public string PartA { get; set; }
public string PartB { get; set; }
public string PartC { get; set; }
}
/// <summary>
/// 构建着 & 抽象类
/// </summary>
abstract class Builder
{
//创建产品对象
protected readonly Product product = new Product();
public abstract void BuildPartA();
public abstract void BuildPartB();
public abstract void BuildPartC();
/// <summary>
/// 返回产品对象
/// </summary>
/// <returns></returns>
public Product GetResult()
{
return product;
}
}
/// <summary>
/// 具体构建者
/// </summary>
class ConcreteBuilder1 : Builder
{
public override void BuildPartA()
{
product.PartA = "A1";
}
public override void BuildPartB()
{
product.PartB = "B1";
}
public override void BuildPartC()
{
product.PartC = "C1";
}
}
/// <summary>
/// 指挥者
/// </summary>
class Director
{
private Builder _builder;
public Director(Builder builder)
{
_builder = builder;
}
public void SetBuilder(Builder builder)
{
_builder = builder;
}
/// <summary>
/// 产品构建与组装方法
/// </summary>
/// <returns></returns>
public Product Construct()
{
_builder.BuildPartA();
_builder.BuildPartB();
_builder.BuildPartC();
return _builder.GetResult();
}
}
#endregion
}
抽象ビルダー型のオブジェクトをコンダクタークラスに注入できます。これは、ビルダーオブジェクトの一部を構築するメソッドが呼び出され、最後に製品オブジェクトが返されるコンストラクターメソッドConstruct()を提供します。
顧客の場合、製品オブジェクトの特定のアセンブリプロセスではなく、特定のタイプのビルダーのみを気にする必要があります。
ユーザーは構成ファイルを介して具象ビルダークラスConcreteBuilder1の名前を保存できるため、新しいビルダーに変更するときにソースコードを変更する必要がなく、システムの拡張がより便利になります。
2.3ビルダーパターンと抽象ファクトリパターンの類似点、相違点、関連性
- 共通点:ビルダーパターンと抽象ファクトリパターンはどちらも、より複雑で創造的なパターンです。
- 違い:焦点が異なります。ビルダーモデルは完全に複雑な製品を返しますが、抽象ファクトリモデルは一連の関連製品を返します。抽象ファクトリモデルでは、クライアントは具体的なファクトリを選択して必要なオブジェクトを生成します。ビルダーモードでは、クライアントは、特定のビルダータイプを指定し、複雑なオブジェクトを段階的に構築して結果を返すことに焦点を当て、オブジェクトを生成する方法についてDirectorをガイドします。
- 関連性:抽象ファクトリモデルを、さまざまな種類の自動車部品を生成する自動車部品製造工場と見なす場合、ビルダーモデルは、部品を組み立てて完全な自動車を返品する自動車組立工場です。
2.4ビルダーモードの適用例
2.4.1説明例
ゲームソフトウェア会社は、ロールプレイングに基づいたマルチプレイヤーオンラインゲームの開発を決定しました。プレイヤーは仮想世界で特定の役割を果たすことができます。役割は、さまざまなゲームプロットと統計(パワー、魔法、スキルなど)に基づいています。能力が異なると、キャラクターはアップグレードを続けるにつれて、より強力な能力を持つようになります。
ゲームの重要な部分として、ゲームのキャラクターをデザインする必要があり、ゲームがアップグレードされると新しいキャラクターが追加されます。分析の結果、ゲームキャラクターは、性別や顔などの複数の要素を含む複雑なオブジェクトであることがわかりました。ゲームキャラクターの種類によって、性別、顔、服装、髪型などの外部特性が異なります。たとえば、「天使」 「彼の顔は美しく、髪型は長い。彼は白いドレスを着ていた。「悪魔」は非常に醜く、頭が禿げていて、まばゆいばかりの黒いドレスを着ていた。
ゲームキャラクターの種類に関係なく、作成手順は同じです。コンポーネントを段階的に作成してから、各コンポーネントを組み立てて完全なゲームキャラクターにする必要があります。次に、ビルダーモードを使用して、ゲームキャラクターの作成を実現します。
2.4.2役割構造図の例
2.4.3サンプルコード
(1)アクター:複雑な製品オブジェクトとして機能するゲームロールクラス。これは、文字列を均一に使用してメンバー変数のデータ型を単純化し、実際の環境での特定の型を実際の状況に応じて定義するケースの説明です。
/// <summary>
/// 游戏角色类,充当复杂产品对象。
/// </summary>
class Actor
{
/// <summary>
/// 角色类型
/// </summary>
public string Type{ get; set; }
/// <summary>
/// 性别
/// </summary>
public string Sex{ get; set; }
/// <summary>
/// 面容
/// </summary>
public string Face{ get; set; }
/// <summary>
/// 服装
/// </summary>
public string Costume{ get; set; }
/// <summary>
/// 发型
/// </summary>
public string Hairstyle{ get; set; }
}
(2)ActorBuilder:抽象ビルダーとして機能するゲームキャラクタービルダー。
/// <summary>
/// 角色建造者:抽象建造者
/// </summary>
abstract class ActorBuilder
{
protected readonly Actor actor = new Actor();
public abstract void BuildType();
public abstract void BuildSex();
public abstract void BuildFace();
public abstract void BuildCostume();
public abstract void BuildHairstyle();
//工厂方法,返回一个完整的游戏角色对象
public Actor CreateActor()
{
return actor;
}
}
(3)HeroBuilder:具体的なビルダーとして機能するヒーローキャラクタービルダー。
/// <summary>
/// 英雄角色建造者,充当具体建造者。
/// </summary>
class HeroBuilder : ActorBuilder
{
public override void BuildType()
{
actor.Type = "英雄";
}
public override void BuildSex()
{
actor.Sex = "男";
}
public override void BuildFace()
{
actor.Face = "英俊";
}
public override void BuildCostume()
{
actor.Costume = "盔甲";
}
public override void BuildHairstyle()
{
actor.Hairstyle = "飘逸";
}
}
他の2つの役割AngelBuilder:エンジェルキャラクタービルダー、DevilBuilder:デビルキャラクタービルダー、どちらも具体的なビルダーとして機能します。上記のコードと同様であり、繰り返されることはありません。
(4)ActorController:ロールコントローラー、ロールコマンダーとして機能します。
/// <summary>
/// 角色控制器,充当角色指挥者。
/// </summary>
class ActorController
{
//逐步构建复杂产品对象
public Actor Construct(ActorBuilder ab)
{
Actor actor;
ab.BuildType();
ab.BuildSex();
ab.BuildFace();
ab.BuildCostume();
ab.BuildHairstyle();
actor = ab.CreateActor();
return actor;
}
}
(5)特定のビルダークラスのクラス名(FullClassName)を構成ファイルに格納する構成ファイルApp.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="builder" value="BuilderPattern.GameCharacter.HeroBuilder"/>
</appSettings>
</configuration>
(6)クライアントプログラムでメインを呼び出す
// 游戏角色结构创建
//xml配置文件与反射方式扩展
// 1.读取【App.config】配置文件,key = builder
string builderType = ConfigurationManager.AppSettings["builder"];
// 2.反射生成对象
ActorBuilder ab = (ActorBuilder)Assembly.Load("BuilderPattern").CreateInstance(builderType);
ActorController ac = new ActorController();
Actor actor = ac.Construct(ab); // 通过指挥者创建完整的建造者对象
Console.WriteLine($"{actor.Type}的外观,性别:{actor.Sex},面容:{actor.Face},服装:{actor.Costume},发型:{actor.Hairstyle}");
3 |取締役の詳細な 議論
3.1ビルダーモードの簡素化
簡略化された方法1:ディレクターを省略
場合によっては、システム構造を単純化するために、Directorと抽象ビルダーBuilderをマージでき、複雑な製品オブジェクトを徐々に構築するためのConstruct()メソッドがBuilderに提供されます。Builderクラスは通常抽象クラスであるため、Construct()メソッドを静的として定義して、クライアントが直接呼び出すことができるようにすることができます。ゲームロールインスタンスのコマンダークラスActorControllerを省略すると、ActorBuilderのコードは次のように変更されます。
abstract class ActorBuilder
{
// 设置对象静态 & 只读并且实例化
protected static readonly Actor actor = new Actor();
public abstract void BuildType();
public abstract void BuildSex();
public abstract void BuildFace();
public abstract void BuildCostume();
public abstract void BuildHairstyle();
// 工厂方法,返回一个完整的游戏角色对象
public Actor CreateActor(ActorBuilder ab)
{
ab.BuildType();
ab.BuildSex();
ab.BuildFace();
ab.BuildCostume();
ab.BuildHairstyle();
return actor;
}
}
簡略化されたメソッド2:Directorを省略し、CreateActor(ActorBuilder ab)メソッドのActorBuilderパラメーターを削除し、このメソッドでthis.BuildXXX()メソッドを直接呼び出し、次のように変更します。
abstract class ActorBuilder
{
// 设置对象静态 & 只读并且实例化
protected static readonly Actor actor = new Actor();
public abstract void BuildType();
public abstract void BuildSex();
public abstract void BuildFace();
public abstract void BuildCostume();
public abstract void BuildHairstyle();
// 工厂方法,返回一个完整的游戏角色对象
public Actor CreateActor()
{
this.BuildType();
this.BuildSex();
this.BuildFace();
this.BuildCostume();
this.BuildHairstyle();
return actor;
}
}
簡素化されたクライアントコール
// 游戏角色结构创建
//xml配置文件与反射方式扩展
// 1.读取【App.config】配置文件,key = builder
string builderType = ConfigurationManager.AppSettings["builder"];
// 2.反射生成对象
ActorBuilder ab = (ActorBuilder)Assembly.Load("BuilderPattern").CreateInstance(builderType);
Actor actor = ab.Construct(); // 通过指挥者创建完整的建造者对象
Console.WriteLine($"{actor.Type}的外观,性别:{actor.Sex},面容:{actor.Face},服装:{actor.Costume},发型:{actor.Hairstyle}");
上記の2つの単純化メソッドは、システムの柔軟性とスケーラビリティに影響を与えず、同時にシステム構造を単純化しますが、抽象ビルダークラスの責任を増大させます。上記のCreateActor()メソッドの内部構造がより複雑で、構築する製品に多くのコンポーネントがある場合は、CreateActor()メソッドをDirectorに個別にカプセル化することをお勧めします。これは、単一責任の原則に沿ったものです。
3.2フック方式の導入
複雑な製品オブジェクトを徐々に構築するだけでなく、ビルダーモードでは、Directorクラスを使用して、製品の作成プロセスをより細かく制御することもできます。たとえば、Hookメソッドと呼ばれる特別なメソッドを追加して、BuildPartX()メソッドを呼び出すかどうかを制御します。 。
フックメソッドの戻り値の型は通常ブール型であり、メソッド名は通常IsXXX()であり、フックメソッドは抽象ビルダークラスで定義されます。たとえば、ゲームキャラクターの抽象ビルダークラスActorBuilderでメソッドIsBareheaded()を定義して、キャラクターが「ベアヘッド」であるかどうかを判断し、ActorBuilderでそのデフォルトの実装を提供すると、その戻り値はfalseになります。codeshow以下のように:
//角色建造者:抽象建造者
abstract class ActorBuilder
{
protected Actor actor = new Actor();
public abstract void BuildType();
public abstract void BuildSex();
public abstract void BuildFace();
public abstract void BuildCostume();
public abstract void BuildHairstyle();
//钩子方法(Hook Method),需要使用 virtual 关键字
public virtual bool IsBareheaded()
{
return false;
}
//工厂方法,返回一个完整的游戏角色对象
public Actor CreateActor()
{
return actor;
}
}
派生クラスの文字が特定の部分(悪魔/髪の部分など)を構築する必要がない場合、対応する具象ビルダーDevilBuilderは親クラスのフックメソッドをオーバーライドし、その値をtrueに変更して返します。
/// <summary>
/// 英雄角色建造者,充当具体建造者。
/// </summary>
class HeroBuilder : ActorBuilder
{
public override void BuildType()
{
actor.Type = "英雄";
}
public override void BuildSex()
{
actor.Sex = "男";
}
public override void BuildFace()
{
actor.Face = "英俊";
}
public override void BuildCostume()
{
actor.Costume = "盔甲";
}
public override void BuildHairstyle()
{
actor.Hairstyle = "飘逸";
}
// 重写覆盖父类的钩子方法
public override bool IsBareheaded()
{
return true;
}
}
同時に、コンダクタークラスActorControllerのコードを次のように変更します。
/// <summary>
/// 角色控制器,充当角色指挥者。
/// </summary>
class ActorController
{
//逐步构建复杂产品对象
public Actor Construct(ActorBuilder ab)
{
ab.BuildType();
ab.BuildSex();
ab.BuildFace();
ab.BuildCostume();
// 通过钩子方法来控制产品部件的构建
if (!ab.IsBareheaded())
{
ab.BuildHairstyle();
}
return ab.CreateActor();
}
}
4 |ビルダーモデルと適用可能な環境の長所と短所
ビルダーモデルの中核は、複数のコンポーネントを含む完全なオブジェクトを徐々に構築し、同じ構築プロセスを適用してさまざまな製品を構築する方法です。ソフトウェア開発では、複雑なオブジェクトを作成し、優れた柔軟性とスケーラビリティが必要な場合は、ビルダーモデルの適用を検討できます。
4.1ビルダーモードの主な利点
- (1)ビルダーモードでは、クライアントは製品の内部構成の詳細を知る必要はありません。製品自体をYanpinの作成プロセスと組み合わせることで、さまざまな製品オブジェクトを作成できます。
- (2)各コンクリートビルダーは比較的独立しており、他のコンクリートビルダーとは関係がないため、コンクリートビルダーや新しいコンクリートビルダーを追加するのに便利であり、ユーザーは異なるコンクリートビルダーを使用して異なる製品ペアを取得できます。イメージリフティングビルダー用にプログラムされているため、新しいコンクリートビルダーを追加しても、元のクラスライブラリのコードを変更する必要はなく、便利な開発と平等な協力の原則が確立されます。
- (3)ユーザーは、製品の作成プロセスをより細かく制御し、複雑な製品の作成ステップをさまざまな注釈に分解して、作成プロセスを明確にすることができ、プログラムを使用して作成プロセスを制御する方が便利です。
4.2ビルダーモードの主な欠点
- (1)ビルダーモードで作成された製品は、一般的に共通点が多く、コンポーネントが類似しています。たとえば、多くのコンポーネントが同じでないなど、製品間の違いが大きい場合、ビルダーモードは使用に適していません。使用範囲は限られています。
- (2)Sanluの内部変更が複雑な場合、この変更を実現するために多くの特定のビルダークラスを定義する必要がある場合があります。その結果、システムが非常に大きくなり、システムの理解が難しくなり、運用コストが高くなります。
4.3ビルダーモードの適用環境
- (1)生成する必要のある製品オブジェクトは複雑な内部構造を持っており、これらの製品オブジェクトには通常、複数のメンバー変数が含まれています。(2)生成される製品オブジェクトの属性は相互に依存しており、生成の順序を指定する必要があります。
- (3)オブジェクトの作成プロセスは、オブジェクトを作成したクラスから独立しています。ビルダーモードでは、リーダークラスを導入することにより、作成プロセスはビルダークラスやクライアントクラスではなく、リーダークラスにカプセル化されます。
- (4)複雑なオブジェクトの作成と使用を分離し、同じ作成プロセスで異なる製品を作成します。