ゲッターとセッターを避け、ユーザー情報を表示する


10

バックグラウンド

私は「クリーンコードブック」を読んでいます。並行して、私は銀行口座などの体操のカタに取り組んでおり、そのルールに固執しています:

体操の9番目のルールは、ゲッターやセッターを使用しないことです。

とても楽しいようで、私はこの原則に同意します。さらに、作者はClean Codeの98〜99ページで、ゲッター/セッターが抽象化を壊し、オブジェクトに問い合わせる必要はないが、オブジェクトに通知する必要があると説明しています。

これは私の心の中で完全に理にかなっており、私はこの原則に完全に同意します。問題は実際に起こります。

環境

たとえば、一部のユーザーをリストし、ユーザーの詳細を表示する必要があるアプリケーションがあります。

私のユーザーは以下で構成されています:

-> Name
   --> Firstname --> String
   --> Lastname --> String
-> PostalAddress
   --> Street --> String
   --> PostalCode --> String

問題

どのように私は行うことができ、または私は私だけ(簡単な情報を表示する必要があるときゲッターを避けるために何ができると私はその特定のフィールドに余分な操作を必要としないことを確認する必要があり(単純でのFirstName値を表示します)ランダム)出力サポート?

頭に浮かぶのは

1つの解決策は、

user.getName().getFirstName().getStringValue()

これは完全に恐ろしいことであり、体操の多くのルールを破り、デメテルの法則を破ります。

別のものは次のようなものです:

String firstName = user.provideFirstnameForOutput();
// That would have called in the user object =>
String firstName = name.provideFirstnameForOutput();
// That would have called in the name object =>
String firstName = firstname.provideFirstnameForOutput();

しかし、私はこのソリューションに慣れていません。それは、デメッターの法則に一致することだけを目的とするメソッドで標準のゲッター/セッターをバイパスするような「高次のアクセサー」のようです...

何か案が ?

回答:


17

ゲッターとセッターを回避するという考えに関する一般的な誤解は、どこでもそれらを回避することです。これは、ユーザーと対話するアーキテクチャーの表面に到達したときに不可能です。

アプリケーションのビジネスロジック部分でゲッターとセッターを使用しないでください。オブジェクトはコンテキストを提供する集約を使用して保護され、メソッドはコマンドとして機能します。

ゲッターとセッターを回避するために、リアクティブプログラミングと同様のソリューションを設計し、監視可能なエンティティを通じてレポートシステムを実装することもできますが、これはアーキテクチャが非常に複雑になり、ユーザーインターフェースに適していても、アプリケーションのCRUDレベルでは意味がありません。

ゲッター/セッターの使用を検討すべきかどうかは、現在作業しているアプリケーションの部分に完全に依存します。ビジネスロジックの場合、ゲッターを使用したユーザーインターフェイスが完全に問題ない場合は、ゲッターを通じて取得した値に基づいてコードの一部を実行しますが、それほど多くはありません(これにより、ロジックが実際にカプセル化されているはずです)ゲッターを呼び出すクラス)。

また、デメテルの法則は、ドットをカウントすることではなく、クラスでゲッターを使用してコンテキスト提供クラスを切り離し、それ自体ではアクセスできないコンポーネントを取得することです。

ユーザー・インターフェースがビジネス・モデルの奥深くに行き過ぎていると思われる場合は、ビュー・モデルをシステムに導入して、モデルの特定の部分を視覚的表現に変換する責任があると考えることができます。


さて、私の提案は、私のドメインエンティティと、プレゼンテーションレイヤーのカスタムDTOとの間のマッパーのようなものであり、アクセサーがいくつかあると思いますか?
mfrachet 2017年

@マージンかなり、はい。
アンディ

このカスケード接続のすべては、答えに感謝して本当に素晴らしい、スムーズに聞こえます;)
mfrachet

2

考えるべき1つの方向は、生データへのアクセスを提供するのではなく、一般的な文字列フォーマットメンバー関数を提供することです。このようなもの:

String lastName = user.formatDescription("$(Lastname)");
String fullName = user.formatDescription("$(Lastname), $(Firstname)");
String abbreviated = user.formatDescription("$(FnAbb). $(LnAbb).");

このアプローチでは、完全なデータをそのまま提供するだけでなく、便利で意味のある方法でデータを変換する手段を提供できます。たとえば、大文字と小文字を区別するトリックをする必要があるかもしれません:

String accountName = user.formatDescription("$(firstname).$(lastname)");

また、一般的に使用される、おそらく複雑なフォーマットを一度定義することもできるので、たとえば、

String fullAddress = user.formatDescription(User.kAddressFormat);

このアプローチのUser優れている点は、個々の文字列をクラスの内部に保持しながら、呼び出し元のコードに大幅に多くの機能を提供することです。ただし、欠点は、formatDescription()数行のコードになるテンプレートメカニズムを実装する必要があることです。

そのため、これは完全に行き過ぎかもしれません。プログラミングの原則は単なるガイドラインであることを忘れないでください。また、別の原則に従うことがKISSの原則に違反している場合は常に、単純な方法でそれを行うのが最善です。したがって、そのようなフォーマットメンバーが少なくともある程度必要でない限り、アクセサベースのアプローチを使用して、簡単にするためにそれを実装することはありません。


5
しかし、これは私にはSRP違反のように見えます。Userテンプレート言語を解析およびコンパイル/解釈するのは、本当にオブジェクトの責任ですか?
イェルクWミッターク

@JörgWMittag必ずしもそうではありません。私が言ったように、KISSの原則が優先されます。そして、Userクラスがこの機能自体を実装する必要があるとはどこにも言いませんでした。そのような機能を必要とするクラスが2つしかない場合は、テンプレート置換メカニズムを独自のクラスに分解することに賭けることができます。これは、User提供する抽象化を、単なるデータコンテナー以上のレベルに引き上げる方法の例を示すためのものです。そして、それがアクセサを回避することのすべてです。つまり、一連のstructs を処理する代わりにOOPを実行することです。
cmaster-モニカを2017年

あなたはKISSが完全に主観的でSRPの目的であることを知っていますか?KISSは何をすべきかについては何も教えません。そして、あなたにとって「シンプル」とは、私にとって「シンプル」ではないかもしれません。KISSやSRPと議論した場合、品質に実際の違いが見られます。
oopexpert 2017
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.