この章では、Lexiを適切に設計するために対処しなければならない七つの問題を それぞれの問題を深く分析し,解を提案した。, 各ソリューションは、擬似コードとオブジェクトモデリング技術のわずかに修正されたバージョンを含む完全に説明され
最後に、各ソリューションは一つ以上のデザインパターンに直接関連付けられます。 この解がその設計パターンの直接実装であることを示した。
七つの問題(それらの制約を含む)とその解決策(参照されるパターンを含む)は次のとおりです。
Document StructureEdit
文書は、文字、線、その他の形状などの”基本的なグラフィカル要素の配置”です。,、それは”文書の総情報コンテンツをキャプチャ”(pp.35)。 文書の構造にはこれらの要素のコレクションが含まれており、各要素は他の要素のサブ構造になることがあります。
問題と制約
- テキストとグラフィックスは同じように扱われるべきです(つまり、グラフィックスはテキストの派生インスタンスではなく、その逆でもありません)。
- 実装は複雑で単純な構造を同じように扱うべきです。 両者の違いを知る必要はありません。,
- 抽象要素の特定の派生物は、特殊な分析要素を持つ必要があります。
ソリューションとパターン
再帰的構成とは、要素の階層構造であり、”より単純な要素からますます複雑になる要素”を構築します(pp.36)。 構造内の各ノードは、自身の子ノードとその親ノードを認識しています。 操作が構造全体に対して実行される場合、各ノードはその子ノードに対して操作を(再帰的に)呼び出します。
これは、ノードのコレクションである複合パターンの実装です。, ノードは抽象基本クラスであり、派生物は葉(単数)または他のノードのコレクション(葉またはコレクションノードを含むことができます)のいずれかです。 親に対して操作が実行されると、その操作は階層の下に再帰的に渡されます。
FormattingEdit
フォーマットは構造とは異なります。 書式設定は、ドキュメントの物理構造の特定のインスタンスを構築する方法です。 これには、テキストを行に分割する、ハイフンを使用する、余白の幅を調整するなどが含まれます。,
問題と制約
- (書式設定)品質、速度、およびストレージスペースのバランス
- 文書構造から独立した(結合されていない)書式設定を維持します。
ソリューションとパターン
コンポジタクラスは、コンポジションのフォーマットに使用されるアルゴリズムをカプセル化します。 Compositorはドキュメントの構造体のプリミティブオブジェクトのサブクラスです。 Compositorには、Compositionオブジェクトの関連インスタンスがあります。, コンポジタがCompose()
を実行すると、関連するコンポジションの各要素を反復処理し、必要に応じてRowおよびColumnオブジェクトを挿入
コンポジタ自体は抽象クラスであり、派生クラスが異なる書式設定アルゴリズム(二重間隔、より広いマージンなど)を使用できるようにします。)
戦略パターンは、この目標を達成するために使用されます。 戦略は、変化するコンテキストに基づいて使用される複数のアルゴリズムをカプセル化する方法です。, この場合、書式設定は、テキスト、グラフィックス、単純な要素などに応じて異なる必要があります。、フォーマットされている。
ユーザーインターフェイスの装飾ディット
ユーザーがドキュメントと対話するために使用するグラフィカルインターフェイスを変更する機能。,
問題と制約
- 編集領域の周りに境界線を持つテキストのページを画定する
- ユーザーがページのさまざまな部分を表示できるようにするスクロールバー
- ユーザーインターフェイスオブジェクトは装飾について知ってはならない
- “装飾のすべての可能な組み合わせ”と要素のサブクラス化によって引き起こされる”クラスの爆発”を避ける(p.44)
ソリューションとパターン
透明エンクロージャを使用することにより、コンポジションの動作を強化する要素をコンポジションに追加できます。, BorderやScrollerなどのこれらの要素は、特異要素自体の特別なサブクラスです。 これにより、組成物を増強し、状態のような要素を効果的に追加することができる。 これらの拡張は構造体の一部であるため、構造体のOperation()
が呼び出されると、それらの適切なOperation()
が呼び出されます。 これは、装飾を使用するために、クライアントが特別な知識や構造とのインターフェイスを必要としないことを意味します。,
これはデコレータパターンであり、オブジェクト自体を変更せずにオブジェクトに責任を追加するパターンです。
複数のルックアンドフィール標準のサポート編集
ルックアンドフィールは、プラットフォーム固有のUI標準を指します。 これらの基準”を定義ガイドラインなどの用途が対応し、ユーザー”(pp.47).
問題と制約
- エディタは、移植性があるように複数のプラットフォームの標準を実装する必要があります
- 新しい緊急の標準に簡単に適応
- ルックアンドフィールの実行時の変更を可能にします(すなわち、,:ハードコーディングなし)
- 要素の各カテゴリ(スクロールバー、ボタンなど)の抽象要素サブクラスのセットを持っています。)
- 抽象サブクラスごとに、異なるルックアンドフィール標準を持つことができる具象サブクラスのセットを持っています。 (MotifscrollbarとPresentationScrollBarを持つモチーフとプレゼンテーションのルックアンドフィール)
ソリューションとパターン
実行時に異なる具象オブジェクトのオブジェクト作成を行うことはできないため、オブジェクト作成プロセスを抽象化する必要があります。, これは、ui要素を作成する責任を負う抽象guiFactoryを使用して行われます。 抽象guiFactoryには、適切な型(MotifScrollBar)の具象要素を作成するMotifactoryなどの具象実装があります。 このようにして、プログラムはスクロールバーを要求するだけで、実行時に正しい具体的な要素が与えられます。
これは抽象的な工場です。 通常の工場をコンクリートの物体のタイプです。 抽象ファクトリは、ファクトリ自体の具体的な実装に応じて、様々なタイプの具体的なオブジェクトを作成します。, 具体的なオブジェクトだけでなく、具体的なオブジェクトのファミリー全体に焦点を当てるその能力は、”一種の製品オブジェクトのみを含む他の創造パターンと区別される”(pp.51)。
マルチウィンドウシステムのサポート編集
プラットフォームによってルックアンドフィールが異なるのと同じように、windowsの処理方法も異なります。 各プラットフォームでは、表示、レイアウト、入力と出力の処理、およびウィンドウのレイヤーが異なり,
問題と制約
- ドキュメントエディタは、存在する”重要でほとんど互換性のないウィンドウシステム”の多くで実行する必要があります(p.52)
- 抽象ファクトリを使用することはできません。 標準が異なるため、各タイプのウィジェットに共通の抽象クラスはありません。
- 新しい非標準のウィンドウシステムを作成しないでください
ソリューションとパターン
“すべてのウィンドウシステムは一般的に同じことを行う”(p.52)ので、”独自の抽象クラスと具象クラス”を開発することが可能です。, 各ウィ
抽象ベースWindow
クラスは、アプリケーション、アイコン化、ダイアログなどの既存のウィンドウの異なるタイプに派生することができます。 これらのクラスには、整形、グラフィカルな更新など、windowsに関連付けられている操作が含まれます。 各ウィンドウには要素が含まれており、そのDraw()
関数はWindow
独自の描画関連関数によって呼び出されます。,
することを回避するために、作成プラットフォーム-特定のウィンドウのサブクラス毎に可能なプラットフォームであり、インターフェースを使用します。 Window
クラスは、Window
実装(WindowImp
)抽象クラスを実装します。 このクラスは、プラットフォーム固有の操作を持つ複数のプラットフォーム固有の実装に派生します。, したがって、Window
クラスのセットのみがWindow
の各タイプに必要であり、WindowImp
クラスのセットのみが(利用可能なすべてのタイプとプラットフォームのデカルト積ではなく)各プラットフォームに必要である。 さらに、新しいウィンドウタイプを追加しても、プラットフォームの実装を変更する必要はありません。
これはブリッジパターンです。 Window
とWindowImp
は異なりますが、関連しています。, Window
プログラム内のウィンドウを扱い、WindowImp
プラットフォーム上のウィンドウを扱います。 そのうちの一つは、他のものを変更することなく変更できます。 ブリッジパターンにより、これら二つの”独立したクラス階層が独立して進化しても一緒に動作する”ことができます(p.54)。
ユーザー操作編集
テキストの入力、書式設定の変更、終了、保存など、ユーザーがドキュメントで実行できるすべてのアクション。,
問題と制約
- 操作は、メニューオプションや同じコマンドのキーボードショートカットなど、異なる入力を介してアクセスする必要があります
- 各オプションには変更可能なインターフェイスがあります
- 操作はいくつかの異なるクラスに実装されています
- 結合を避けるために、実装とユーザーインターフェイスクラスの間に多くの依存関係があってはなりません。,
- Undoおよびredoコマンドは、ほとんどのドキュメント変更操作でサポートされなければなりません。undoのレベル数に任意の制限はありません。
- 関数は、undo/redoが容易ではなく、状態に容易に関連付けられず、拡張または再利用が困難であるため、実行可能ではありません。
- メニューは階層的な複合構造のように扱われるべきです。 したがって、メニューは、他のメニュー項目などを含む可能性のあるメニュー項目を含むメニュー項目である。,
ソリューションとパターン
各メニュー項目は、パラメータのリストでインスタンス化されるのではなく、コマンドオブジェクトで行われます。
コマンドは、単一の抽象Execute()
メソッドのみを持つ抽象オブジェクトです。 派生オブジェクトは、Execute()
メソッドを適切に拡張します(つまり、PasteCommand.Execute()
はコンテンツのクリップボードバッファを利用します)。 これらのオブジェクトは、メニュー項目で使用できるのと同じくらい簡単にウィジェットやボタンで使用でき,
undoとredoをサポートするために、Command
にはUnexecute()
とReversible()
も与えられます。 派生クラスでは、前者はそのコマンドを元に戻すコードを含み、後者はコマンドが元に戻すことができるかどうかを定義するブール値を返します。 Reversible()
保存コマンドなど、一部のコマンドを元に戻すことができません。
実行されたすべてのCommands
は、最近実行されたコマンドの直後に”現在”マーカーを保持する方法でリストに保持されます。, 元に戻すリクエストは、”present”の直前にCommand.Unexecute()
を呼び出し、”present”を一つのコマンドに戻します。 逆に、Redo
リクエストは、”present”の後にCommand.Execute()
を呼び出し、”present”を前方に移動します。
このCommand
アプローチは、コマンドパターンの実装です。 でカプセル化の要求のオブジェ用に関する共通インターフェースからアクセスする。 このように、クライアントに対応でき異なる要求は、コマンドを使用することができ至る所に散りばめられます。,
スペルチェックとハイフネーション編集
これは、文書の内容をテキストで分析するドキュメントエディタの機能です。 実行できる分析はたくさんありますが、スペルチェックとハイフネーションの書式設定が焦点です。
問題と制約
- スペルをチェックし、ハイフネーションの場所を特定するための複数の方法を可能にします
- 将来の分析(単語数、文法チェックなど)のための拡張を可能にします
- テキストの実際の構造にアクセスすることなく、テキストの内容を反復処理することができます(例えば、, 配列、リンクリスト、文字列)
- ドキュメントのトラバーサルの任意の方法を可能にします(始めから終わり、終わりから始まり、アルファベット順など)。)
ソリューションとパターン
基本要素から整数ベースのインデックスを削除すると、異なる反復インタフェースを実装することができます。 このするための方法のためのフォーカストラバーサルおよびオブジェクト検索。 これらのメソッドはabstractIterator
インターフェイスに配置されます。, 各要素は、その要素がリストをどのように保持するかに応じて、Iterator
の派生を実装します(ArrayIterator
、LinkListIterator
など)。).
トラバーサルと検索のための関数は、抽象イテレータインタフェースに入れられます。 将来のイテレータは、配列やリンクリストなど、反復処理するリストのタイプに基づいて派生できます。 したがって、要素の実装が使用するインデックスメソッドのタイプに関係なく、適切なイテレータを持ちます。
これはイテレータパターンの実装です。, これにより、クライアントは、コレクションのコンテンツに直接アクセスしたり、コレクションの構造が使用するリストのタイプを心配することなく、
トラバーサルが処理されたので、構造の要素を分析することができます。 各タイプの分析を要素構造自体に構築することは不可能であり、すべての要素をコード化する必要があり、コードの多くは同様の要素で同じになります。
代わりに、汎用のCheckMe()
メソッドが要素の抽象クラスに組み込まれます。, 各イテレータには、特定のアルゴリズム(スペルチェック、文法チェックなど)への参照が与えられます。). その反復子がコレクションを反復処理すると、各要素のCheckMe
を呼び出し、指定されたアルゴリズムを渡します。 CheckMe
次に、その要素への参照を分析のために前記アルゴリズムに戻します。
したがって、スペルチェックを実行するために、フロントツーエンドのイテレータにSpellCheck
オブジェクトへの参照が与えられます。, 次に、イテレータは各要素にアクセスし、CheckMe()
メソッドをSpellCheck
パラメーターで実行します。 それぞれのCheckMe
は、SpellCheck
を呼び出し、適切な要素への参照を渡します。
このようにして、任意のアルゴリズムを任意のトラバーサル方法で使用することができ、ハードコードを他方と結合することなく使用できます。 たとえば、”前方”イテレータが使用されたか、”後方”イテレータが使用されたかに応じて、Findは”次を検索”または”前を検索”として使用できます。,
さらに、アルゴリズム自体が異なる要素を扱う責任を負うことができます。 たとえば、SpellCheck
アルゴリズムは、Graphic
要素を無視し、すべてのGraphic
派生要素をSpellCheck
に送信しないようにプログラムする必要はありません。