web-dev-qa-db-ja.com

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

背景

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

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

とても楽しいようで、私はこの原則に同意します。さらに、クリーンコードの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();

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

何か案が ?

10
mfrachet

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

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

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

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

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

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

17
Andy

考えるべき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原則に違反しているときはいつでも、単純な方法でそれを行うのが最善です。そのため、少なくともこのようなフォーマットメンバーが必要でない限り、私はアクセサベースのアプローチを使用して、単純化のために実装する必要はありません。