導入: なぜスケーラブルエンジニアリングソフトウェアは、抽象的な工場パターンを必要とする

エンジニアリングソフトウェアは、要件、ハードウェアプラットフォーム、およびコンポーネントファミリーの迅速な変化を処理しなければなりません。 有限要素解析ツール、CADシステム、または組み込み制御ファームウェアの構築に関係なく、アーキテクチャは、コアロジックを書き換えることなく、新しいセンサー、アクチュエータ、ソルバー、またはUIコンポーネントのシームレスな統合をサポートする必要があります。 []]Abstract Factory Pattern]]]は、四種の生成パターンの1つで、関連するオブジェクトの生成をカプセル化するための実証済みの方法を提供します。 高度な機能と、および、すべてのクライアントの拡張機能が、すべてのクライアントの拡張機能が維持されます。

この記事では、パターンの構造を探索し、エンジニアリングコンテキストで現実的な実装を歩き、それを適用するときに議論します(そして、オーバーエンジニアリングを避けるために)。 アブストラクトファクトリーが、コードベースを横断して変化することなく進化する仕様に適応するシステムを構築するのに役立つかを確認します。

抽象的な工場パターンを理解する

コア定義

Abstract Factory Pattern は、具体的なクラスを指定せずに関連オブジェクトや依存オブジェクトの家族を作成するためのインターフェイスを提供します。 単一の工場が一緒に作業するように設計されている複数の製品タイプを生成できるようにする抽象化に依存しています。 パターンには、次の主要な参加者が含まれます。

  • []AbstractFactory] — それぞれの製品ファミリーメンバーの1組の創作方法を宣言します。
  • ConcreteFactory] — 特定のバリエーション(例えば、ハードウェアプラットフォームA)のために具体的な製品を生産するための作成方法を実行します。
  • []AbstractProduct] — は、製品の種類(例えば、センサー)のインターフェイスを宣言します。
  • [ConcreteProduct] — 対応するConcreteFactoryによって生成される製品を定義します。
  • [Client] — AbstractFactoryとAbstractProductインターフェイスのみを使用します。

使い方

クライアントコードは、AbstractFactory(多くの場合、構成またはランタイム選択を介して注入)のインスタンスを受け取ります。 コンクリート工場がそれらを生成したことを知らずに、工場の創作方法を呼び出します。 コンクリートオブジェクトは、同じ家族から来るので、互換性のあることが保証されます。 これは、エンジニアリングシステムが複数のバリアントを持っているときに特に価値があります(例えば、異なるハードウェアリビジョン、異なるシミュレーション物理モデル)。

例えば、エンジニアリングデータ取得システムでは、高周波センサーと対応する高速スタンピングアクチュエータの両方を「HighSpeedFactory」が生成される場合があります。 「LowPowerFactory」は、低周波センサーと低電力アクチュエータを生成します。 クライアントは、特定のものを知らなくても、 ] と だけを呼び出します。

エンジニアリングソフトウェアの利点

アブストラクトファクトリーパターンは、エンジニアリングシステムの課題に直接対処するいくつかの利点を提供しています。

  • 柔軟性]:アプリケーションがどの工場で使用しているかを変更することで、コンポーネントの家族全体をスワップします。これは、ビジネスロジックに触れることなく、複数のハードウェアプラットフォーム、シミュレーションエンジン、またはUIツールキットをサポートするのに最適です。
  • :拡張性:新しい家族(例えば、新しいセンサーのブランドをサポートする)を追加するには、新しいコンクリート工場とその製品を実装するだけです。 既存のコードは、未修正のままで、オープン/クローズド原則に付着します。
  • [: オブジェクト作成ロジックが一元化されます。コンストラクタのシグネチャの変更が起きた場合、そのクラスをインスタンス化するすべての場所ではなく、対応する工場のみを更新します。
  • テスタビリティ:ユニットテストでは、スタブ付きコンポーネントを生成するモックファクトリーを提供できます。クライアントコードは変更されず、テストがより速く、より信頼性が高くなります。
  • [Portability]: エンジニアリングソフトウェアは、さまざまなオペレーティングシステムやハードウェア構成で実行する必要があります。 アブストラクトファクトリーでは、プラットフォーム固有のUIダイアログ、ファイルアクセスレイヤー、またはネットワークスタックを共通のインターフェイスの背後に配置できます。

実践におけるパターンの実装

Step-by-Step の実装

抄録工場パターンをエンジニアリングソフトウェアに適用するには、次の手順に従ってください。

  1. []製品ファミリーを特定 — 一緒に使用しなければならないオブジェクトのグループを決定します。 構造解析ツールでは、物理ドメイン(例えば、線形静的対非線形動)1家族として[]、、および[[[]]を持っているかもしれません。
  2. [] 抽象的な製品インタフェース[] — 製品タイプごとに一つのインターフェイスを作成します。例えば: []]、、]]。
  3. 抽象的な工場インターフェイス[]を作成するための宣言方法:、、[]]。
  4. ] コンクリート工場 — 各家族()と[)のために、適切なコンクリート製品クラスを返す方法の具体的な実装を提供します。
  5. [ クライアント[]] を設定 — クライアントは、抽象的な工場(依存性注射、構成ファイル、または単純なランタイムの決定)のインスタンスを受け取ります。 それから、工場を使用して、必要なコンポーネントを作成します。

例:FEAソルバーファミリー

複数の物理フィニト要素解析プラットフォームを構築していると想像してみてください。異なる解析タイプには、異なるソルバーとプリプロセッシングツールが必要です。Abstract Factoryを使用すると、このようなコードを構成できます(言語 - agnostic スタイルでpseudo-code)。

// Abstract products
interface ISolver {
 void Solve();
}
interface IMeshGenerator {
 Mesh Generate();
}

// Abstract factory
interface ISolverFactory {
 IMeshGenerator CreateMeshGenerator();
 ISolver CreateSolver();
}

// Concrete factory for linear static analysis
class LinearStaticFactory : ISolverFactory {
 IMeshGenerator CreateMeshGenerator() => new LinearStaticMeshGen();
 ISolver CreateSolver() => new DirectSolver();
}

// Concrete factory for nonlinear dynamic analysis
class NonlinearDynamicFactory : ISolverFactory {
 IMeshGenerator CreateMeshGenerator() => new NonlinearMeshGen();
 ISolver CreateSolver() => new IterativeSolver();
}

// Client code
class AnalysisEngine {
 private ISolverFactory factory;
 public AnalysisEngine(ISolverFactory factory) {
 this.factory = factory;
 }
 public void Run() {
 var mesh = factory.CreateMeshGenerator().Generate();
 var solver = factory.CreateSolver();
 solver.Solve();
 }
}

解析タイプを切り替えるには、別の工場でエンジンを生成するだけで、他のコードの変更はありません。このパターンは、さまざまな物理モジュールをサポートする多くの商用FEAパッケージで使用されます。

リアルワールドシナリオ:組込みシステムのためのハードウェア抽象化

自律ドローン用のファームウェアを開発するエンジニアリングチームを検討してください。 ドローンの飛行コントローラーは、複数のセンサースイート(GPS、IMU、barometer)とアクチュエータタイプ(ESC、サーボ)をサポートしなければなりません。 各ハードウェアリビジョンは、異なる通信プロトコル(I2C、SPI、UART)を使用します。 アブストラクトファクトリーパターンは、ファームウェアがドローンの変種を横断してポータブルになることを可能にします。

抽象的な工場[は、]のような方法を定義します。のような具体的な工場および[]]は実際のハードウェアに話す具体的な製品を作り出します。 フライトコントローラーのクライアントコードは抽象的なインターフェイスに依存します。 新しいセンサーのリビジョンが到着すると、飛行制御アルゴリズムを変更することなく新しい工場が追加されます。 これは、テストと努力を劇的に低下させます。

ユニットテストにも、このような抽象化も価値があります。シミュレートセンサー読み取りを返すモック工場を注入し、物理的なハードウェアなしで継続的な統合を可能にします。

関連パターンとの比較

抽象的な工場対工場方法

[Factory Method]パターンは、単一のメソッド(多くの場合、仮想)を使用して、一種の製品を作成します。 これは、よりシンプルですが、単品のみで動作します。 アブストラクトファクトリーは、複数の関連製品を取り扱ってい、互換性のある製品を保証します。 工場方法を使用して、必要な製品種だけを1つだけ使用してください。 一緒に使用しなければならない製品の家族を持っているときに、Abstract Factoryを使用してください。

抽象的な工場対ビルダー

[Builder]パターンは、建設プロセスを制御する取締役と、ステップで複雑なオブジェクトのステップを組み立てることに焦点を当てています。 ビルダーは、製品が複数のステップを必要とするときに理想的です(例えば、CADモデルを組み立てます)。 アブストラクトファクトリーは、通常、既に完了します。 彼らは組み合わされることができます - アブストラクトファクトリーは、ビルダーが組み立てる個々の部品を作成することができます。

アブストラクトファクトリー対依存注入(DI)

DIコンテナ(例えば、スプリング、.NETコアDI)は、多くの場合、フードの下にAbstract Factoryパターンを使用します。 コンテナ内のコンクリート工場を登録し、コンテナが解決できるようにすることができます。 パターン自体は同じままです。 DIはただ配線を自動化します。

最高の練習と落札

アブストラクト工場のご使用時

  • 貴社のシステムは、製品が作成、構成、または表現する方法とは独立する必要があります。
  • 複数の家族が一緒に使う製品を提案します。
  • 製品の種類に一貫性を強制したい。

一般的なピトル

  • オーバーアブストラクション:すべての小さなバリエーションのための工場を追加することで、不要な複雑さを引き起こします。 あなたが本当に一緒に変更する複数の製品家族を持っている場合は、評価します。
  • []too多くの製品タイプ:あなたの抽象的な工場インターフェイスが大きく成長する場合(例えば、10 +メソッド)、小規模な工場に分割するか、レジストリのアプローチを使用して検討してください。
  • [Performance オーバーヘッド]: パフォーマンスクリティカルな組み込みシステムでは、追加の間接が問題になる可能性があります。このような場合には、言語が許可するか、慎重にプロファイルをする場合は、コンピレーション タイム ポリモルフィズム(templates/generics)を使用します。

コンテンツ

Abstract Factory Patternは、複数のコンポーネントファミリーをサポートしなければならないスケーラブルで保守可能なエンジニアリングソフトウェアを構築する実証済みの方法です。オブジェクトの作成をカプセル化することで、プラットフォーム固有の詳細からコアアルゴリズムを解放し、簡単に拡張、テスト、および適応を可能にします。マルチフィジックスシミュレーションソルバー、ドローン用のハードウェア抽象的なレイヤー、またはモジュラーCADアプリケーションを設計しているかどうかにかかわらず、Abstract Factoryはオブジェクトの家族を管理するための明確な構造を提供します。適切な依存性注射とアーキテクチャを組み合わせて、あなたの要件を整理します。

さらなる研究については、元の[]を参照してください。Wikipediaエントリ]、決定的]])、Guruガイドをリファクタリングするか、またはに深く潜る]]。パターンをジューシャスに適用し、あなたのエンジニアリングソフトウェアは明日の課題に準備が整います。