web-dev-qa-db-ja.com

肥大化したGUIコードの作成を回避するにはどうすればよいでしょうか。

GUIコードを操作するときはいつでも、コードが他の種類のコードより速く膨らむ傾向があることを発見しました。また、リファクタリングするのも難しいようです。他の種類のコードではかなり簡単にリファクタリングできますが、大きなクラスを小さな機能に分解できます-ほとんどのGUIフレームワークでは、多くの場合、ウィジェット/コントロール/その他のクラスが必要なフレームワークにバインドされていますウィジェット/コントロール/何でももっと多くのものを直接実装します。これは、(a)一部の基本ウィジェット/コントロール/ものから継承するか、(b)保護されたメソッドにアクセスする必要があるために発生することがあります。

また、ユーザーとやり取りするすべてのモードを実装するには、通常、フレームワークからの信号/イベント/その他を介してさまざまな入力に応答する必要があります。以下を含む多種多様な入出力を処理するために、1つのGUIウィジェット/コントロールで必要になる場合があります。

  1. 右クリック/コンテキストメニュー
  2. コンテキストメニューからの選択に反応する-多くの場合があります
  3. gUIをペイントする特別な方法
  4. キーボード入力に反応する
  5. ボタン、チェックボックス、
  6. などなど

...その間、ビジネスロジックを表すGUIの下でクラスを管理します。

単純な単純なGUIは、ビジネスロジックを分離してMVCを使用している場合でも、コードがすぐに大きくなる可能性があります。

健全な方法でGUIコードを管理し、壊れたウィンドウになるのを防ぐ方法はありますか?または、大量のランダムイベントハンドラー/オーバーライドされたメソッドが本当にGUIコードに対して実行できる最善の方法ですか?

48
Doug T.

GUIコードについて覚えておくべきことは、それがイベント駆動型であり、イベント駆動型コードは常にランダムに編成されたイベントハンドラーの集合体のように見えることです。それが本当に面倒になるのは、イベント駆動型ではないコードをクラスに押し込もうとするときです。確かに、それはイベントハンドラーのサポートを提供しているように見え、イベントハンドラーを小さく小さく保つことができますが、その余分なサポートコードがすべて浮かんでいるため、GUIソースが肥大化し、乱雑に見えます。

では、これについて何ができ、どのようにしてリファクタリングを簡単にできるでしょうか?さて、最初に、リファクタリングの定義を、時々行うことから、コーディングしながら継続的に行うことに変更します。どうして?コードをより簡単に変更できるようにリファクタリングしたいからであり、その逆ではありません。ここでセマンティクスを変更するようにお願いするだけでなく、コードを別の方法で見るために少し精神体操をするようにお願いします。

私が最もよく使用する3つのリファクタリング手法は、名前の変更メソッドの抽出、およびクラスの抽出です。他のリファクタリングを1つも学習しなかった場合でも、これらの3つを使用しても、コードをクリーンで適切に構造化することができます。質問の内容から、同じ3つのリファクタリングをほぼ常に使用しているように思われるかもしれません。 GUIコードを薄くてきれいに保つために。

世界でGUIとビジネスロジックを可能な限り分離することができますが、GUIコードはコードマインがその真ん中で爆発したように見えます。私のアドバイスは、GUIを適切に管理するのに役立つ追加のクラスを1つまたは2つ用意しても問題ないことです。MVCパターンを適用する場合、これは必ずしもViewクラスである必要はありません。 -中間クラスがビューに非常に似ていることがよくあるので、便宜上、それらをマージしたいという衝動を感じることがよくあります。私の見解では、すべてのビジュアルロジックを管理するためにGUI固有のレイヤーを追加することは実際には問題ありませんが、そうすることの利点とコストを比較検討する必要があるでしょう。

したがって、私のアドバイスは次のとおりです。

  • GUIがビュー(または中間層)にフックする方法を呼び出して定義することを除いて、GUIのすぐ後ろで何もしません。
  • 意味がない限り、ビューに関連するすべてのものを1つのクラス、またはGUIウィンドウごとに1つのクラスに分類しようとしないでください。あなたの代わりはあなたのGUIロジックを管理するためにたくさんの小さくて簡単に管理できるクラスを作成することです。
  • メソッドが4〜5行のコードより少し大きく見え始めたら、これが必要かどうか、およびクラスを意味する場合でもメソッドをリーンに保つことができるように1つまたは2つのメソッドを抽出できるかどうかを調べます。より多くの方法で。
  • クラスが非常に大きく見え始めている場合は、重複する機能をすべて削除してから、メソッドを論理的にグループ化して、別のクラスを抽出できるかどうかを確認します。
  • コード行を記述するたびにリファクタリングを検討してください。コード行が機能するようになったら、機能を重複させないようにリファクタリングできるか、または動作を変更せずに少し無駄を省くことができるかどうかを確認してください。
  • 特に、リファクタリングを怠った場合、システムの一部が少し肥大化し始めると常に感じることは避けられません。十分に因数分解されたコードベースを使用しても、couldを実行することで、それ以上のものがあるように感じることができます。これはソフトウェアを書くことの現実であり、より良い何かが「より良く」できるはずだといつも感じているので、専門家の仕事と金メッキのバランスをとる必要があります。
  • コードをきれいに保ち続けると、コードの肥大化が少なくなることを受け入れてください。
36
S.Robins

あなたが経験している問題の多くは、単純な原因にさかのぼることができると思います。 ほとんどの開発者はGUIコードを「実際の」コードのように扱いません。ここには証拠も統計もありませんが、私の直感だけです。

多分彼らはそれを「単なるプレゼンテーション」で重要ではないと考えています。 「そこにはビジネスロジックはありません」と彼らは言う、「ユニットテストを行う理由 '?オブジェクト指向に言及してクリーンなコードを書くと、彼らは笑います。彼らは物事をより良くするために試みさえしません。始めるための構造はありません。彼らはいくつかのコードを平手打ちし、他の人が時間をかけて自分のタッチを追加するときにそれを腐敗させます。美しい混乱、落書きコード。

GUIコードには独自の課題があるため、異なる方法で、また尊重する必要があります。それを書くには、愛と開発者wantが必要です。それを薄く保ち、それに良い構造と正しいパターンを与えるもの。

23
c_maker

何らかの理由で、GUIコードは、懸念の分離について開発者に盲点を作成します。すべてのチュートリアルがすべてを1つのクラスにまとめているためかもしれません。多分それは、物理的な表現が物事をそれらがよりもより密接に結合して見えるようにするからです。たぶんそれは、クラスがゆっくりと構築されるため、人々がリファクタリングの必要性を認識しないためです。

理由が何であれ、解決策はクラスをはるかに小さくすることです。これを行うには、入力しているものを別のクラスに入れることが可能かどうかを継続的に自問します。別のクラスに入れることが可能で、そのクラスの合理的で単純な名前が考えられる場合は、それを行います。

8
Karl Bielefeldt

モデルビュープレゼンター/パッシブビューのパターンを確認することをお勧めします。 Ray RyanはGoogleで良い講演をしましたIO GWTのベストアーキテクチャプラクティスについて。

http://www.google.com/events/io/2009/sessions/GoogleWebToolkitBestPractices.html

他のフレームワークや言語にアイデアを抽象化するのは簡単です。 MVP(私の意見では)の主な利点は、単体テスト可能性です。そして、あなたがそれを得るのは、肥大化もスパゲッティもされていないあなたのコード(あなたの質問で判断すると、これはあなたが望むものです)の場合です。プレゼンターと呼ばれるビューロジックレイヤーを導入することで機能します。実際のビューは、インターフェースを介してこれから切り離されています(したがって、単体テストで簡単に模擬できます)。これで、ビューロジックレイヤー(プレゼンター)が具象GUIフレームワークの内部から解放されるため、通常のコードのように整理でき、たとえば、 Swings継承階層。理想的には、同じインターフェースに準拠している限り、異なるフレームワークでGUI実装を切り替えることができます。

6
scarfridge

私の答えは、構造、単純さ、テスト、構文の4つの部分で構成されています。

最初の3つは本当に難しいです!

構造は、最小量のコードと最大量のフレームワーク、ライブラリなどの使用に多くの注意を払うことを意味します。

Simplicityは、初期設計から実際の実装まで、物事をシンプルに保つことを意味します。ナビゲーションをシンプルに保ち、シンプルなプラグインを使用し、レイアウトをかなり 'プレーン'に保つことはすべてここで役立ちます。 PC、iPad、モバイル、その他のデバイスで動作するページの利点をすぐに確認できるクライアント/ユーザーに「販売」できるようになりました。

Testingは、より適切なコードを設計できる場合にクロスブラウザーの問題を前もってキャッチするブラウザーテストツール(webratとcapybaraがmy Rails work)を思い付く)を含めることを意味しますさまざまなブラウザーのユーザーによって「発見」されるため、さまざまな開発者が頻繁にコードを「パッチング」するのではなく、最初にそれらに対処します。

構文コードチェッカー/ IDE/editor-pluginなど)をHTML、CSS、Javascriptなどに使用すると非常に便利です。ブラウザの利点不正な形式のHTMLを処理することで得られる機能は、ブラウザによって動作が異なる場合に動作します。そのため、HTML形式をチェックするツールが不可欠です。整形式のHTMLがあると、HTMLが肥大化していないため、不正なコードの視認性が高くなります。 。

5
Michael Durrant

ここにはたくさんの素晴らしい答えがあります。

GUIコードを簡略化するのに役立つ1つのことは、GUIに独自のデータモデルがあることを確認することです。

簡単な例を挙げると、4つのテキスト入力フィールドを持つGUIがある場合、それら4つのテキスト入力フィールドの内容を保持する別のデータクラスがあります。より複雑なGUIには、より多くのデータクラスが必要です。

GUIをモデルとして設計します-ビュー。 GUIモデルは、アプリケーションモデル-ビュー-コントローラーのアプリケーションコントローラーによって制御されます。アプリケーションビューは、GUIコード自体ではなく、GUIモデルです。

4

私が見つけた解決策は宣言型コードです。手続き型コードだけを使用することは、スパゲッティGUIコードのレシピです。確かに、「ウィジェットをペイントする特別な方法」はおそらくコードのままです。しかし、これはクラスで分離されたコードです。イベントハンドラー、キーボードショートカット、ウィンドウサイズ-面倒なものはすべて宣言するのが最善です。

4
MSalters

ワードプロセッシング、グラフィックエディターなどのアプリケーションには複雑なインターフェイスがあり、そのコードは単純ではありません。ただし、ビジネスアプリケーションの場合、GUIはそれほど複雑である必要はありませんが、いまだに複雑なものもあります。

GUIを簡略化するためのいくつかのキーは(ほとんどが.NETに適用されます):

  1. 可能な限りシンプルなデザインを目指します。ビジネスから要求されない場合は、派手な行動を避けます。

  2. 適切なコントロールプロバイダーを使用します。

  3. クライアントコード自体にカスタムコントロール機能を作成しないでください。代わりに、元のコントロールを拡張するユーザーコントロールを作成して、使用するフォーム/ページのコードではなく、コントロールに特定の動作を反映できるようにします。

  4. フレームワーク(自作の場合でも)を使用して、国際化、リソース管理、スタイルなどを処理し、すべてのUIでこのコードを繰り返さないようにします。

  5. ナビゲーション用のコンポーネント(またはフレームワーク)を採用します。

  6. エラー、警告、確認などの標準的なダイアログを構築する.

2
NoChance

オブジェクト指向設計をコードに適用し、UI開発のために:

  1. プレゼンテーションとモデルを分離するMV-whateverライブラリ/フレームワークを使用するか、独自に作成して、ビュー/コントローラーロジックをデータモデルから分離します。バックエンドとのすべての通信はモデル内で行う必要があり、モデルの状態は常にバックエンドと同期している必要があります。
  2. DecouplingオブジェクトAがオブジェクトBについて知っている場合、AはBのメソッドを呼び出すことができますが、BはAについて知っているべきではありません。代わりに、AはB.循環依存がないことを確認します。アプリのコンポーネント間に多数のイベントがある場合は、EventBusを作成するか、Twitter Flightなどのイベント駆動型フレームワークを活用します。
  3. 部分的なレンダリングと完全なレンダリングビューがテーブルまたはアイテムのリストである場合、「add」、「remove」などのメソッドを作成して挿入したくなるかもしれません/コレクションから/アイテムを1つ削除します。並べ替えとページ付けをサポートする必要がある場合、コードが簡単に肥大化する可能性があります。したがって、私のアドバイスは、部分的な変更があった場合でも、ビュー全体を再レンダリングするだけです。パフォーマンスはどうですか?コレクションが大きい場合でも、とにかくページネーションを行う必要があります。 Web開発者:イベントハンドラーが、変更されないビューのルート要素に委任されていることを確認してください。
  4. ビューモデルたとえば、ビューの状態が複雑すぎて維持できない場合、テーブルビューは行データ、列データ、並べ替え順序を追跡する必要があります。 、現在チェックされている行(マルチチェックをサポートしている場合)など、おそらくこれらの状態のViewModelオブジェクトを作成する必要があります。 UIで何かが変更された場合(たとえば、ユーザーが行をチェックした場合)、ViewオブジェクトはViewModelのセッターを呼び出す必要があります。また、UIを更新することにより、ViewModelの変更イベントに応答する必要があります。通常、変更イベントがUIによってトリガーされる場合は、UIの更新を避ける必要があります。

これは、私のポイントのいくつかを説明するのに役立つ、小さくても重要なアプリです。ここでコードとビュー/モデルの相互作用図を見つけることができます: https://github.com/vanfrankie/pushpopbox

1
frank

"databinding" の概念を見てみましょう。これは、モデル要素がUIのコンテンツと自動的に同期されるように、宣言的な方法でUI要素を抽象モデル要素に接続する方法です。このアプローチには多くの利点があります。たとえば、データを同期するためにイベントハンドラーを自分で作成する必要はありません。

。NETEclipse/JFace など、多くのUIフレームワークのデータバインディングサポートがあります。

0
JesperE