
当社では、管理者がExcelを使用して従業員の運用負荷を計画しました。 MS Projectのような複雑なものを使用する必要はありませんでした。 しかし、しばらくの間、テーブルは要件を満たすのをやめ、スプレッドシートに埋め込まれたスクリプトの機能を拡張するのは楽しい作業ではありません。
そのため、アプリケーションを作成するように求められました。 しかし、最初はトラクターを要求し、最終的には戦闘機が必要であることがわかります。 そこで、創造性の開発に取り組むことにしました。 この記事では、最終的に作成したもの、選択したアーキテクチャ、およびその利点を説明します。
最初は、ツールのインターフェースの基礎は、従業員とプロジェクトの2つのテーブルになるように計画されていました。 従業員をプロジェクトにドラッグアンドドロップして、労働時間を割り当てることができます。

アプリケーションは、Flex(+ AIRランタイム)で作成することが決定されました。 フレームワークには、必要なものがすべて含まれています。 AdvancedDataGridコンポーネントは、従業員およびプロジェクトテーブルの基盤として機能します。 レンダラーにより非常に柔軟で、ドラッグアンドドロップのプラグインサポートが便利です。 AIRはマルチウィンドウアプリケーションをサポートしており、ファイルを操作できます。
まず、基本的な要件の概要を説明します。
基本的な要件
1.カスタマイズの柔軟性を表示する開発のごく初期から、インターフェースの利便性を向上させるためのアイデアが頭に浮かび始めました。 顧客ごとにプロジェクトをグループ化し、プロジェクト間の関係をドラッグアンドドロップする機能を追加し、従業員とプロジェクトをフォルダにドラッグしてから、複数のドキュメントを異なるウィンドウで同時に開きたいという要望がありました。 プレゼンテーションを制御ロジックから可能な限り分離し、構成の柔軟性を提供する必要があることが明らかになりました。
2.異なる論理ブロックの独立した包含の容易さと、それらの間のコマンド送信の信頼性ホットボタン、新しいデータストレージ形式、その他のデータソース(サーバー、エクスポート、インポート、履歴、その他の多くの追加機能など)のサポートが必要になります。 そしてそれが起こった。
3.アーキテクチャは信頼性を確保する必要があります新しいエラーを回避するために、新しい機能の追加はできるだけシンプルにする必要があります。 明示的に必要ない場合は、既に実装されている機能に影響を与えません。
受信した要件に従って開発するには、mateなどのイベントに基づいた既製のフレームワークを使用できますが、パターンを知っている場合は、システムを自分で組み立てることがより興味深いです。
1.カスタマイズの柔軟性を表示する
MVCに似た回路を使用します。 モデル、ビュー、コントローラーに類似した3つのコンポーネント:
DataBuilder 、
Viewおよび
Engineがあります。
DataBuilder (モデル)はデータを保存し、データを操作するための基本的なロジックを提供します。 彼だけが、パラメーターの初期セットからデータ項目を作成する方法を知っています。 DataBuilderは、すべてのエンジンでデータ要素のファクトリとして使用されます。 これにより、同じメソッドを使用して要素が正しく作成されます。
ビューはdataBuilderデータにアクセスできます。 便宜上、このデータはdataBuilderの静的変数に保存され、どこからでもアクセスできます。 また、ビューはエンジンのコマンドで更新され、必要に応じてデータを表示します。 さらに、ビューはユーザーのアクションに応じてコマンドをエンジンに送信します。
エンジン (コントローラー)はビジネスロジックを処理します。
次の作業スキームが判明します。

したがって、dataBuilder-engine-viewには、従業員用とプロジェクト用の2つのトリプルがあります。 また、アーキテクチャには、ビューやdataBuilderがないシステムがあります。 それについては以下に書かれます。
2.プログラムのモジュール構造で、その部分間の信頼性の高い通信
異なるエンジンの独立した組み込みの容易さと、同時に、それらの間のコマンドの転送の信頼性を達成する必要があります。
責任の連鎖パターンを実装します。 エンジンは連鎖されます。 チェーンの最初のエンジニアは、チェーンに沿って目的地に進むコマンドを送信します。
最初に、各エンジンに識別子
public static const TYPE:Stringを追加します。 すべての識別子は異なっていなければなりません。 それらの一意性は、それを作成しなければならないエンジン工場で検証されます。
コマンドは、
Eventから継承した
CommandEventクラスを使用して渡されます。 これには
commandType:Stringフィールドがあり、このコマンドの宛先となるエンジンのタイプが渡されます。 このイベントには、エンジンがさまざまなアクションを実行できるように、チームを改良するための一連のフィールドもあります。 たとえば、要素の追加、プロパティの一部の変更、
ビューの更新、ファイルの読み取りまたは書き込み。

それでは、チェーンを組み立てましょう。 特定のすべてのエンジンは、いくつかの定義済みフィールドとメソッドを持つAbstractEngineクラスを継承します。
-Nextには、チェーン内の次の要素へのリンクが含まれます。
-activate(イベント)メソッドは抽象です。 各エンジンの特定の動作が実装されているサブクラスで再定義されます。
-
ハンドル(イベント)メソッドは、指定されたエンジンが着信タイプでコマンドを処理しているかどうかを確認します。 はいの場合、
activate()が実行され
、そうでない場合、チェーン内の次のエンジンの
handle()メソッドが呼び出されます。
したがって、コマンドを回線に転送するには、ルート要素で
ハンドル()を呼び出すだけです。 チェーンが機能するために、
アプリケーションで、ルートエンジンは
CommandEventにサブスクライブします。
rootEngine.addEventListener(CommandEvent.ACTIVATE、rootEngine.handle);
アプリケーションで使用されるすべてのブロックは、下の図に示されています。

既に述べたように、engine-dataBuilder-viewには、従業員用とプロジェクト用の2つのトリプルがあります。
データのないシステムがあります:
CommandPanel (ビュー)とそれに
CommandEngine 。 これは、各ウィンドウの上部にあるパネルです。 彼女はコマンドの送信のみを扱います。
ビューのないシステムがあります。従業員とプロジェクトの関係を定義するオブジェクト用です。 これは
BindsBuilder-BindsEngineのペアです。 関係ビューは
EmployeesViewと
ProjectsViewの両方に含まれています。
最後に、プレゼンテーションとデータのない複数のエンジンがあります:
InputOutputEngine (XMLファイルを使用)、
CSVEngine (テーブルを使用)、
ShortCutsEngine (ホットキーを使用)。
このアーキテクチャにより、新しいブロックを簡単に追加できます。 たとえば、最初は外部形式をサポートすることを意図していませんでした。 しかし、ツールの開発の終わりまでに、CSVエクスポート/インポート機能を追加する必要が生じました。 これを行うには、
CSVEngineをチェーンに追加します。
InputOutputEngineとほぼ同じ
ですが 、別のデータパーサーが含まれているだけです。 次に、対応するイベントを送信するボタンを
コマンドパネルに追加します。 これで、アプリケーションでCSVを使用できるようになりました!
システム全体が非同期で動作するため、サーバーからデータを受信する機能の実装に大きな障害はありません。
アーキテクチャの利点
まず、チェーンが機能するには、イベントのルートエンジンに署名するだけで十分です。 その後、エンジンをチェーンに追加および削除するだけで、エンジンをオンまたはオフにできます。
次に、各エンジンはチェーンを通過するコマンドを変更できるため、柔軟性が向上します。 どのエンジンも、現在のコマンドをチェーンに渡す前に、いくつかの追加コマンドを他のエンジンに送信できます。 このようにして、1つのコマンドで一連のアクションをトリガーできます。 たとえば、新しいファイルを開くコマンドは、現在のファイルを保存し、新しいファイルを読み取り、解析してから、ビューを更新します。
このアーキテクチャのもう1つの利点は、開発プロセスの簡素化です。 各エンジンのロジックはカプセル化されています。 これにより、複数の人が競合することなく、一度に1つのアプリケーションで作業できます。
表示リストオブジェクトからチェーンにコマンドを送信するのは非常に簡単です。
バブル== true のイベントが
Applicationにポップアップし、チェーンに入ります。 これは、ユーザーが
ビューのいずれかでボタンをクリックすることを想定した作業図です。

3.サポート履歴とホットキー
最後のアクションを取り消すことができない現代のソフトウェアではどうですか?
アーキテクチャにより、ストーリーのサポートを簡単に追加できます。
最初は、ストーリーはMementoパターンに基づいて作成されました。 各アクション後のこのアプリケーションの状態は、Mementoに保存できるxml-objectに一意に変換されます。 しかし、実際のデータの場合、xmlテーブルの完全な更新は遅すぎて、約1〜2秒であることがわかりました。 したがって、私はより複雑な方法を使用する必要がありました。ユーザーのアクションごとにリバースアクションを作成して記憶し、[元に戻す]が押されたときに順番に呼び出すということです。
履歴マネージャーは、直接アクションと逆アクションのセットを2つの配列に格納します。 エンジンはコマンドを受け取ると、ストーリーの中でそれらに直接および逆のコマンドを追加します。 元に戻すまたはやり直しを押すと、配列から目的のコマンドを取得して、
dispatchEvent()を呼び出すだけで十分です。 すべてのエンジンは、それをビューから来た通常のコマンドとして認識し、適切なアクションを実行します。
CommandEventの操作は 、Commandパターンに非常に似ています。 違いは、「受信者」パターンではコマンドにカプセル化され、
CommandEventでは、コマンドはエンジン(「受信者」の役割を果たす)が処理するかどうかを決定するタイプのみを持つということです。 原則として、
addHandableCommand()を使用して手動で追加した場合、どのエンジンでも他のコマンドの処理を開始できます。
ホットキーも簡単に実装できます。 それらのマネージャーは、
CommandEventおよびこのコマンドを呼び出すキーの組み合わせを含む
Shortcutクラスのインスタンスを格納します。 ボタンをクリックすると、組み合わせが表示されます。 組み合わせが配列内にある場合、対応するタスクが実行されます。

ソースコードと手順を含むアプリケーションは、Googleコードにあります。
code.google.com/p/easyworkloadtool結論
要件を完全に満たすアプリケーションを設計しました。 確実に機能し、新機能の拡張と追加の可能性はほぼ無限です。 そのアーキテクチャにより、各従業員が独自にエンジンを操作できるため、単一のプログラマーとチームの両方で便利に開発およびサポートできます。
説明したアーキテクチャは、ほとんどすべてのクライアントアプリケーションの開発に使用できます。 さまざまな修正を加えて、多くのプロジェクトで使用されています。