金属切削機用のCAD/CAMソフトウェアを管理しています。だから私はこの問題についていくらかの経験を持っています。
私たちが最初にソフトウェアを変換したとき(1985年に最初にリリースされました!)、オブジェクト指向設計に変換しました。私はあなたが気に入らないことをしました。オブジェクトとインターフェイスには、Draw、WriteToFileなどがありました。変換の途中でデザインパターンを見つけて読むことは大いに役立ちましたが、それでも多くの悪いコードの臭いがありました。
やがて私は、これらのタイプの操作のどれも実際にはオブジェクトの関心事ではないことに気づきました。むしろ、さまざまな操作を実行するために必要なさまざまなサブシステム。これは、現在パッシブビューコマンドオブジェクトと呼ばれているものと、ソフトウェアのレイヤー間で明確に定義されたインターフェイスを使用して処理しました。
私たちのソフトウェアは基本的にこのように構成されています
- さまざまなフォームインターフェイスを実装するフォーム。これらのフォームは、UIレイヤーにイベントを渡すものシェルです。
- イベントを受信し、フォームインターフェイスを介してフォームを操作するUIレイヤー。
- UIレイヤーは、すべてコマンドインターフェイスを実装するコマンドを実行します
- UIオブジェクトには、コマンドが対話できる独自のインターフェイスがあります。
- コマンドは、必要な情報を取得して処理し、モデルを操作してからUIオブジェクトにレポートします。UIオブジェクトは、フォームで必要なすべてのことを実行します。
- 最後に、システムのさまざまなオブジェクトを含むモデル。シェイププログラム、カッティングパス、カッティングテーブル、金属シートなど。
したがって、描画はUIレイヤーで処理されます。マシンごとに異なるソフトウェアがあります。したがって、すべてのソフトウェアが同じモデルを共有し、同じコマンドの多くを再利用します。彼らは非常に異なる描画のようなものを扱います。たとえば、カッティングテーブルは、ルーターマシンとプラズマトーチを使用するマシンでは、どちらも本質的に巨大なXYフラットテーブルであるにもかかわらず、描画が異なります。これは、車のように2台の機械が十分に異なって製造されているため、顧客にとって視覚的な違いがあるためです。
形は以下の通りです
入力したパラメータを通る切断パスを生成する形状プログラムがあります。カッティングパスは、どの形状プログラムが生成されたかを認識しています。ただし、切断経路は形状ではありません。画面に描画したり、形を切り取ったりするために必要な情報だけです。この設計の理由の1つは、外部アプリからインポートするときに、シェイププログラムなしでカットパスを作成できることです。
この設計により、必ずしも同じものではない形状の設計から切断経路の設計を分離することができます。あなたの場合、パッケージ化する必要があるのは、形状を描くために必要な情報だけです。
各シェイププログラムには、IShapeViewインターフェイスを実装する多数のビューがあります。IShapeViewインターフェイスを介して、シェイププログラムは、一般的なシェイプフォームに、そのシェイプのパラメータを表示するように設定する方法を通知できます。汎用シェイプフォームはIShapeFormインターフェイスを実装し、ShapeScreenオブジェクトに登録します。ShapeScreenオブジェクトは、それ自体をアプリケーションオブジェクトに登録します。シェイプビューは、アプリケーションに登録されているシェイプスクリーンを使用します。
さまざまな方法で形状を入力することを好む顧客がいるという複数のビューの理由。私たちの顧客ベースは、形状パラメーターを表形式で入力するのが好きな人と、その前の形状のグラフィック表現で入力するのが好きな人の間で半分に分かれています。また、フルシェイプの入力画面ではなく、最小限のダイアログからパラメータにアクセスする必要がある場合もあります。したがって、複数のビュー。
形状を操作するコマンドは、2つのカテゴリのいずれかに分類されます。切断パスを操作するか、形状パラメータを操作します。形状パラメータを操作するには、通常、形状入力画面に戻すか、最小限のダイアログを表示します。形状を再計算し、同じ場所に表示します。
カッティングパスでは、各操作を個別のコマンドオブジェクトにまとめました。たとえば、コマンドオブジェクトがあります
ResizePath RotatePathMovePathSplitPathなど。
新しい機能を追加する必要がある場合は、別のコマンドオブジェクトを追加し、右側のUI画面でメニュー、キーボードショート、またはツールバーボタンスロットを見つけて、そのコマンドを実行するようにUIオブジェクトを設定します。
例えば
CuttingTableScreen.KeyRoute.Add vbShift+vbKeyF1, New MirrorPath
また
CuttingTableScreen.Toolbar("Edit Path").AddButton Application.Icons("MirrorPath"),"Mirror Path", New MirrorPath
どちらの場合も、コマンドオブジェクトMirrorPathは目的のUI要素に関連付けられています。MirrorPathのexecuteメソッドには、特定の軸のパスをミラーリングするために必要なすべてのコードがあります。コマンドには独自のダイアログがあるか、UI要素の1つを使用して、ミラーリングする軸をユーザーに尋ねる可能性があります。これは、訪問者を作成したり、パスにメソッドを追加したりするものではありません。
アクションをコマンドにバンドルすることで、多くのことを処理できることがわかります。ただし、それは黒または白の状況ではないことに注意してください。それでも、元のオブジェクトのメソッドとして特定のものがうまく機能することがわかります。経験上、メソッドで行っていた作業のおそらく80%をコマンドに移動できたことがわかりました。最後の20%は、オブジェクトに対して単純に機能します。
カプセル化に違反しているように見えるため、これを好まない人もいるかもしれません。私たちのソフトウェアを過去10年間オブジェクト指向システムとして維持してきたことから、あなたができる最も重要な長期的なことは、ソフトウェアのさまざまなレイヤー間およびさまざまなオブジェクト間の相互作用を明確に文書化することです。
アクションをコマンドオブジェクトにバンドルすることは、カプセル化の理想へのスラブな献身よりも、この目標に役立ちます。パスをミラーリングするために必要なことはすべて、パスのミラーリングコマンドオブジェクトにバンドルされています。