私は常にほとんどのクラス プロパティに getter と setter を提供してきました。
私はこれが悪いと読んだが - http://www.codeweavers.net/getters-and-setter-are-evil/
依存性注入と単体テストでは、ほとんどのプロパティにセッターが必要ですか?
私は常にほとんどのクラス プロパティに getter と setter を提供してきました。
私はこれが悪いと読んだが - http://www.codeweavers.net/getters-and-setter-are-evil/
依存性注入と単体テストでは、ほとんどのプロパティにセッターが必要ですか?
ゲッターとセッターは常に使用する必要があります。ゲッターまたはセッターの理由は、内部プロパティへのパブリック インターフェイスを提供することではなく、プロパティの読み取り/書き込みを制御することです。これらは、クラス プロパティの抽象化を提供します。
クラスのプロパティでさえプライベートであるため、ゲッターとセッターが必要です。これにより、割り当てまたは読み取りの直前に値を制御できます。
読み取りごとに共通の計算を行う、かなり前に設計したクラスについて考えてみてください。
class A{
private decimal x;
public void do_stuff(){
decimal a = this.x/70;
// process with a
}
public void do_anoter_stuff(){
decimal a = this.x/70;
// process again a
}
}
次に、係数 (70) を変更します。どのようにしますか?あちこち変える?このように設計する方が良いでしょう。
class A{
private decimal x;
private get_x(){ return this.x/70; }
public void do_stuff(){
// process with get_x()
}
public void do_anoter_stuff(){
// process again get_x()
}
}
事実は、すべてのプロパティにゲッターとセッターを盲目的に使用することは悪です。経験則です。プライベート ゲッターとセッターを使用して、すべてのプロパティをプライベートとして宣言します。必要に応じて外界からのアクセスのみを許可するように、後でゲッターとセッターの可視性を変更します
その記事が言っていることは、オブジェクト指向はデータのカプセル化と動作の提供を意味するということです。プロパティを提供することで、データをカプセル化していません。たとえば、次のAccount
ようなクラスを実装できます。
public class Account
{
public decimal Balance { get;set; }
}
しかし、それは概念的には次のことと変わりません。
public class Account
{
public decimal Balance;
}
どちらの場合も、クラスには動作がありません。で動作するすべての動作は、 のAccount
外部にある必要がありますAccount
。この記事が言っていることは、行動と状態は共存すべきだということです。したがって、代わりに次のようなものがあるかもしれません:
public class Account
{
private decimal balance;
//...
public void DepositFunds(Money money)
{
balance += ValidateAndConvert(money);
}
public void WithdrawFunds(Money money)
{
balance -= ValidateAndConvert(money);
}
public void AdjustBalance(Money money)
{
balance -= ValidateAndConvert(money);
}
private decimal ValidateAndConvert(Money money)
{
// TODO: validate, convert
}
}
プロパティまたはフィールドとして残高を持つ勘定科目を使用すると、外部ロジックで必要に応じて残高を変更できます。これは通常、ビジネス ロジックをコード ベース全体に分散させます。口座から資金を引き出すためのロジックが残高をチェックし、口座が過剰引き出しできないこと、または特定の金額だけ過剰引き出しできないことを確認する必要がある場合、コード内の多くの場所でそのロジックを提供する必要があります。多くの場所を変更する必要があるそのロジックを見つけて変更する必要がある場合 (1 つのリスクが見逃され、一貫性のない引き出しが発生する)。データがオブジェクト内にカプセル化され、動作のみが提供される場合、そのロジックをコード ベースに分散させる方法はありません。これにより、より明示的なコードも可能になります。account.Balance -= someValue;
撤回、調整などだった可能性があります。今では明示的にできます。account.Widthdraw(someValue);
または account.AdjustBalance(someOtherValue);`--アカウントに何が起こっているかが明確です。
その記事が言っていることは、パブリックのゲッターとセッターを介してプライベート データを公開してはならないということです。すべてのメンバーに getter と setter を使用することは、暗黙のうちに間違っているわけではありません (実際には、実際にはすべてのプライベート変数を気にする人はほとんどいませんが、それは良い考えだと主張する人もいます ... 私はまだ実際にそうしている人に会ったことがありませんとりあえず)
悪い考えは、すべての変数に公開のゲッターとセッターを用意することです。これにより、カプセル化が不十分なクラスがほぼ保証されます。
C++ では、フレンドシップを使用してプライベート アクセスを回避し、ホワイト ボックス テストを提供することができます。他の言語でも他のメカニズムを使用して同じことができると思いますが、よくわかりません (C++ で商業的に開発されたものはすべて、 Java と C# で楽しみのために書いたアプリはテストしません)。おそらくリフレクションは、探している動作を許可します。
必要でない限り、ゲッター/セッターを追加しません。そうしないと、変更が必要なときに他のクラスがどのデータ/メソッドに依存しているかを知るのが難しくなります。さらに、ゲッター/セッターの使いすぎは、データのカプセル化がすべてである不十分なオブジェクト指向設計の兆候である可能性があります。
ゲッターは確かに状態ベースのユニット テストに役立ちますが、テスト クラスだけがアクセスできるようにスコープを制限することを検討することもできます。または、equals
メソッドを作成して、クラス自体で等価性チェックを行うこともできます。
依存性注入を使用すると、ゲッターを回避できます。代わりに、注入モック オブジェクトによる相互作用ベースのテストを実行できるためです。