a 形式のメソッドを作成する最も論理的に一貫した方法は b に影響しますか?
https://softwareengineering.stackexchange.com/questions/17173
-
22-10-2019 - |
質問
よくあるシナリオでは、別のオブジェクト (b) に論理的に影響を与えるオブジェクト (a) があります。たとえば、a が b にメモを付けたり、a が b を無効にマークしたりするなどです (通常、a はシステムのユーザー オブジェクトで、b は何らかのオブジェクトです)顧客や約束などのビジネス オブジェクトの一種)。
以前は、メソッドは次のような影響を受けるオブジェクトにありました。
customer.Disable(user); // user is marking the customer as disabled
...しかし、うまく読めません(逆に表示されます)。反対:
user.Disable(customer);
...読みやすさは向上しましたが、何か正しくないと思われる、私には指摘できない点があります。他の唯一のオプションは、静的な仲介者を使用することです。
ThirdPartyClass.DisableCustomer(customer, user);
...しかし、ドメイン オブジェクトは最終的には DTO に似てきます。私はドメイン モデルのアプローチの方が理にかなっているので好みます。
そこで質問は次のとおりです。どれが最も理にかなっていますか?検討していないオプションはありますか?このような運営を実際に行っているのは誰ですか?
編集
2 番目のオプションでは、システム内の実行可能なオブジェクト (通常はユーザー) が巨大になります。これは、システムのユーザーがほとんどすべてのことを実行し、影響を与えるためです。
解決
どうでしょうか
customer.SetDisabledBy(user);
または、C# 4.0 または同様の機能を持つ別の言語を使用している場合:
customer.SetDisabled(by: user);
または、C# 3.5 以降を使用している場合は、次のように記述できます。
user.DisableCustomer(customer);
DisableCustomer メソッドを、というクラスにある拡張メソッドにします。 CustomerActions
それは一緒に座っています Customer
クラス。そうすれば、あなたがいるとき、 using
の Customer
名前空間、 User
その拡張メソッドがあります。そうでないときは using
それ、なくなってしまった。 User
はもはや神オブジェクトではありませんが、中間クラスはコードのどこにも見つかりません。あなたも持っているかもしれません OrderActions
提供するクラス user.CancelOrder(order)
, 、など。
良い質問で、考えさせられました!
他のヒント
user.Disable(customer)
ほとんどそう言ってるように見える user
無効化されているため、 user.Disable()
顧客ではなくユーザーに作用しているように読めます。
user.DisableCustomer(customer)
顧客が無効にされていることが明確になるため、もう少し読みやすくなると思います。また、単に目的のためだけに追加のクラスが必要ないということも意味します。
ユーザー オブジェクトが非常に多くの役割を担っており、「user.DoFooOnBar(bar)」メソッドが多すぎるように感じられる場合は、神オブジェクトである可能性があります。インターフェースを使用してユーザーの役割をドメイン固有の部分に分割するか、構成を使用して同じことを行うと、気分が良くなる場合があります。
インターフェース
User が実装する ICustomerController インターフェイスがあり、ユーザーが顧客を無効にする必要がある場合は、顧客を ICustomerControl にキャストし、ICC.DisableCustomer(customer) を使用できます。これは、顧客がユーザーではなく「顧客を操作する何か」によって操作されているため、自然な動きの読み取りを提供します。
また、必要に応じて、ユーザーではない人が顧客を更新できるようにするための柔軟性も高まります。
構成
前回のアイデアの単なる拡張です。ユーザーは ICustomerController (IS-A) ではなく、ICustomerController (HAS-A) を所有することになります。したがって、呼び出しは user.CustomerController.Disable(customer) として読み取られます。繰り返しになりますが、これにより、ユーザーは特定の能力 (顧客に影響を与えるため) で、その 1 つのオブジェクト ドメイン (顧客) に対してのみ行動していることが明確になります。
その問題については言及していませんでしたが、 user.Disable() のようなメソッドは、ユーザー自体を含むあらゆるものに影響を与える可能性があります。上記のいずれかで修正されます。
あなたが指摘したように、User クラスに多くのメソッドがあることにより、 神オブジェクトのアンチパターン. 。問題はカプセル化の 1 つであるようです。そのため、データ フローは
ユーザーがエンティティに対してアクションを実行する
次のように再解釈できます
システムは、エンティティに対してコマンドを実行します。 ユーザーへの参照
これは、次のような典型的なコマンドを持つコマンド パターンの使用を好む設計を意味します。
public class DisableCustomerCommand implements EntityCommand<Customer,User> {
// This is the single EntityCommand templated method
public Customer execute(Customer customer, User user) {
customer.setEnabled(false);
// TODO Add in audit code for User object
return customer;
}
}
これは、ほとんど機能しないが十分に機能する、粒度の高い単純なオブジェクトを作成するという一般的な OOD 原則に従います。
編集
これは単純化しすぎであることを指摘しておく必要があります。通常、顧客を無効にするには、他のいくつかのフィールドを変更する必要があります。また、これはエンティティの貧血にもつながりますが (顧客は単なるゲッター/セッターの集まりになります)、場合によっては、全体的な設計がより単純になる場合もあります。