27

私は多くの場所で「ゲッターとセッターは悪だ」と読みました。そして、私はその理由を理解しました。しかし、それらを完全に回避する方法はわかりません。Item は、アイテム名、数量、価格などに関する情報を持つクラスであり、ItemList はアイテムのリストを持つクラスです。総計を見つけるには:

int grandTotal()
{
int 合計 = 0;

for (アイテム item: itemList)
       合計 += item.getPrice();

合計を返します。
}

上記の場合、getPrice() を回避するにはどうすればよいでしょうか? Item クラスは、getName、setName などを提供します。

どうすればそれらを回避できますか?

4

15 に答える 15

45

ゲッターとセッターはいつ使用する必要がありますか?

ゲッターとセッターは、クラスの構成を構成または決定したり、モデルからデータを取得したりするのに最適です。

アイテムの価格を取得することは、ゲッターの完全に合理的な使用法です。これは利用可能である必要があるデータであり、セッターに検証またはサニタイズを追加することによってデータを保護するための特別な考慮事項が含まれる場合があります。

セッターなしでゲッターを提供することもできます。彼らはペア来る必要はありません。

いつゲッターとセッターを使うべきではありませんか?

オブジェクトは、公開されることのない内部プロパティに依存している場合があります。たとえば、イテレータと内部コレクション。内部コレクションを公開すると、劇的に否定的で予期しない結果が生じる可能性があります。

また、たとえば、HttpURLConnectionを介して通信しているとします。HttpURLConnectionのセッターを公開すると、データの受信を待機している間に接続が変更された場合に、非常に奇妙な状態になる可能性があります。この接続は、インスタンス化時に作成するか、内部で完全に管理する必要があります。

概要

すべての目的と目的のために公開されているが、管理する必要があるデータがある場合は、ゲッターとセッターを使用します。

取得する必要があるが、いかなる状況でも変更してはならないデータがある場合:セッターではなくゲッターを使用します。

内部目的で設定する必要があり、公開してはならない(インスタンス化時に設定できない)データがある場合:セッターを使用しますが、ゲッターは使用しません(セッターはおそらく内部プロパティに影響を与える2番目の呼び出しを防ぎます)

完全に内部的なものがあり、他のクラスがそれにアクセスしたり直接変更したりする必要がない場合は、どちらも使用しないでください。

セッターとゲッターはプライベートにすることができ、内部で管理されているプロパティの場合でも、プロパティを管理するセッターが望ましい場合があることを忘れないでください。たとえば、接続文字列を取得して、それをHttpURLConnectionのセッターに渡します。

また注意してください:

アレン・ホーラブの記事ゲッターとセッターのメソッドが悪である理由は、OPの推論の源であるように思われますが、私の意見では、この記事はそのポイントを説明するのに不十分です。

編集:要約を追加
編集2:スペル修正

于 2012-02-23T17:35:00.540 に答える
19

小さな声の少数派が「ゲッターズアンドセッターズ」全体に対して反発するのを見るのは残念です。まず、記事のタイトルは、他のブログ投稿と同様に、意図的にあなたを引き込むように挑発します。私はこれについて前にブログを書き、数年後にこの質問についての私の意見やアイデアを更新しました。ここで私ができる最善のことを要約します。

  • ゲッターとセッター(アクセサー)は悪ではありません
  • ただし、ほとんどの場合、これらは「悪」(不要)です。
  • カプセル化は、変更を制御するためにプライベートフィールドの周りにアクセサーを追加するだけではありません。結局のところ、プライベートフィールドを変更するだけのget/setメソッドを追加するメリットはありません。
  • 「教えて、聞かないで」の原則でできるだけ多くのコードを書くべきです
  • フレームワークコード、DTO、シリアル化などにアクセサーを使用する必要があります。これと戦おうとしないでください。
  • ただし、コアドメインロジック(ビジネスオブジェクト)を可能な限りプロパティフリーにする必要があります。オブジェクトの内部状態を自由にチェックするのではなく、オブジェクトに何かを行うように指示する必要があります。

アクセサがたくさんある場合は、本質的にカプセル化に違反します。例えば:

class Employee
{
   public decimal Salary { get; set; }

   // Methods with behaviour...
}

私はこれを行うことができるので、これはがらくたドメインオブジェクトです:

me.Salary = 100000000.00;

これは単純な例かもしれませんが、プロの環境で働く人なら誰でも証明できるように、公開されているコードがあれば、それを利用します。開発者がこれを確認し、給与を使用してコードベースの周りに大量のチェックを追加し始めて、従業員をどうするかを決定することは間違いではありません。

より良いオブジェクトは次のとおりです。

class Employee
{
   private decimal salary;

   public void GivePayRise()
   {
        // Should this employee get a pay rise.
        // Apply business logic - get value etc...
        // Give raise
   }

   // More methods with behaviour
}

今では、給与が公の知識であると信頼することはできません。従業員に昇給をしたい人は誰でもこの方法でこれをしなければなりません。このためのビジネスロジックが1つの場所に含まれているため、これは素晴らしいことです。これを1つの場所に変更して、従業員が使用されるすべての場所に影響を与えることができます。

于 2012-02-29T21:48:18.257 に答える
15

次のサンプルは、ボイラープレート セッターとゲッターの優れた例です。

class Item{
  private double price;

  public void setPrice(final double price){
    this.price = price;
  }
  public double getPrice(){
    return this.price;
  }
}

一部のコーダーは、これをカプセル化と呼んでいると考えていますが、実際には、このコードは

class Item{
  public double price;
}

どちらのクラスpriceも保護もカプセル化もされていませんが、2 番目のクラスの方が読みやすくなっています。

 class Item{
    private double price;

    public void setPrice(final double price){
      if(isValidPrice(price))
        this.price = price;
      else throw new IllegalArgumentException(price+" is not valid!");
    }

    public double getPrice(){
      return this.price;
    }
  }

これは実際のカプセル化であり、クラスの不変式は によって保護されていsetPriceます。私のアドバイス -ダミーのゲッターとセッターを作成しないでください。ゲッターとセッターは、クラスの不変式を保護する場合にのみ使用してください。

于 2012-02-23T15:54:19.060 に答える
7

私は多くの場所で「ゲッターとセッターは悪だ」と読みました。

本当に?それは私にはクレイジーに聞こえます。たくさんの?1つ見せてください。ずたずたに引き裂きます。

そして、私はその理由を理解しました。

私はしません。私にはクレイジーに思えます。あなたは誤解しているが、理解したと思っているか、元の情報源がおかしいだけです。

しかし、それらを完全に回避する方法はわかりません。

すべきではありません。

回避する方法はgetPrice

ほら、なぜそれを避けたいのですか?オブジェクトからデータを取得するには、他にどのような方法があると思いますか?

それらを回避する方法???

しないでください。クレイジーな話を読むのはやめましょう。

于 2012-02-23T15:43:50.383 に答える
5

ゲッターとセッターは悪だと誰かが言ったら、なぜそう言っているのか考えてみてください。

ゲッター

彼らは悪ですか?コードになどありません。コードはコードであり、良くも悪くもありません。読み取りとデバッグがどれほど難しいかだけの問題です。

あなたの場合、ゲッターを使用して最終価格を計算してもまったく問題ないと思います。

悪"

ユースケース: 何かを購入するときにアイテムの価格が必要だと思います。

次のようなゲッターを使用することがあります。

if(item.getPrice() <= my_balance) {
   myBank.buyItem(item);
}

このコードに問題はありませんが、それほど単純ではありません。これを見てください(より実用的なアプローチ):

myBank.buyItem(item); //throws NotEnoughBalanceException

何かを購入するときに商品の価格を確認するのは、バイヤーやレジ係の仕事ではありません。それは実際には銀行の仕事です。顧客ASimpleBank.java

public class SimpleBank implements Transaction {

  public void buyItem(Item item){
     if(getCustomer().getBalance() >= item.getPrice()){
        transactionId = doTransaction(item.getPrice());
        sendTransactionOK(transactionId);
     }
  }
}

ここでは、最初のアプローチは問題ないようです。しかし、顧客Bが持っている場合はどうなりますNewAndImprovedBank.javaか?

public class NewAndImprovedBank implements Transaction {

  public void buyItem(Item item){
     int difference = getCustomer().getBalance() - item.getPrice();
     if (difference >= 0) {
        transactionId = doTransaction(item.getPrice());
        sendTransactionOK(transactionId);
     } else if (difference <= getCustomer().getCreditLimit()){
        transactionId = doTransactionWithCredit(item.getPrice());
        sendTransactionOK(transactionId);
     }
  }
}

最初のアプローチを使用すると防御的だと思うかもしれませんが、実際にはシステムの機能を制限しています。

結論

許可を求めるのではなく、代わりitem.getPrice()に許しを求めてくださいNotEnoughBalanceException

于 2015-12-15T11:57:04.480 に答える
3

getPrice() は、私が想定しているプラ​​イベート変数にアクセスしています。

質問に直接答えるには、price 変数を public にして、次のようなコードを作成します (言語、ポインターの使用などによって構文が異なる場合があります)。

total += item.price;

ただし、これは一般的に悪いスタイルと見なされます。クラス変数は通常、プライベートのままにする必要があります。

質問に対する私のコメントをご覧ください。

于 2012-02-23T15:49:59.543 に答える
2

ゲッターとセッターを回避する方法は?保持しているデータに実際に作用する設計クラス。

ゲッターはとにかくデータについて嘘をつきます。このItem.getPrice()例では、を取得していることがわかりますint。しかし、価格はドルまたはセントですか?税金は含まれていますか?別の国や州の価格を知りたい場合でも使用できますgetPrice()か?

はい、これはシステムが行うように設計されている範囲を超えている可能性があります。はい、メソッドから変数の値を返すだけになる可能性がありますが、ゲッターを使用してその実装の詳細をアドバタイズすると、APIが弱くなります。

于 2013-03-09T00:06:07.123 に答える
2

これまでのところ、ここに欠けている別の視点: getter と setter は、Tell Don't Askの原則に違反することを誘います!

あなたがスーパーマーケットに買い物に行くと想像してみてください。結局、レジ係はあなたからお金を欲しがっています。ゲッター/セッターのアプローチは、財布をレジ係に渡し、レジ係が財布のお金を数え、借りているお金を受け取り、財布を返すというものです。

それがあなたが実際に物事を行う方法ですか?全くない。現実の世界では、通常、「自律的な」他の「オブジェクト」の内部状態は気にしません。レジ係は、「あなたの請求書は 5,85 米ドルです」と言います。それからあなたは支払います。レジ係が望む/必要とする唯一のことは、彼があなたの側からその金額を受け取ることです.

したがって、状態ではなく動作の観点から考えると、ゲッターとセッターを回避できます。ゲッター/セッターは、「外側」から状態を操作します ( andを実行することにより。代わりに、.avail = purse.getAvailableMoney()purse.setAvailableMoney(avail - 5.85)person.makePayment(5.85)

于 2019-03-14T09:45:01.553 に答える
1

Cloudanger の答えは 1 つですが、アイテム リストには、注文された数量が記載された多くのアイテム オブジェクトが含まれる可能性が高いことも認識しておく必要があります。

解決策 : それらの間に別のクラスを作成して、アイテムをアイテム リストに格納し、そのアイテムの注文数量を格納します (クラスが OrderLine と呼ばれるとしましょう)。

OrderLine には、フィールドとして Item と qty があります。

その後、price*qty を返す Item に calculateTotal(int qty) のようなコードを記述します。calculateTotal(qtyOrdered) を呼び出す OrderLine のメソッドを作成します。

戻り値を itemList に渡します。

このようにして、ゲッターを回避します。ItemList は合計価格のみを認識します。あなたのコードはあなたのデータと共に生きるべきです。totalPrice を計算する生データをそのオブジェクトに要求するのではなく、データを持っているオブジェクトに totalPrice を計算するように要求します。

于 2014-09-23T23:40:02.313 に答える
1

Javaでゲッターとセッターを避ける方法は? Project Lombokを使用する

于 2012-02-24T16:28:23.823 に答える
0

本当に?そうは思いません。逆に、ゲッターとセッターは変数の一貫性を保護するのに役立ちます。

getter と setter の重要性は、private 属性を保護して直接アクセスできないようにすることですitem。対応する get と set を含む属性を持つクラスを作成することをお勧めします。

于 2012-02-23T15:48:40.730 に答える
0

ヘルパー クラスを使用しShoppingCartます。Itemのメソッドは、次を使用してカートの にitem.addTo(ShoppingCart cart)価格を追加しますtotalSumshoppingCart.addItem(Item item, int price)

s が s のアイテムであることが意図されている場合、 からItemへの依存ShoppingCartは不利ではありません。ItemShoppingCart

sがItemのためだけに存在しShoppingCartItemクラスが小さい場合、がアイテムのプライベート変数にアクセスできるように、Itemを の内部クラスとして使用する可能性が高くなります。ShoppingCartShoppingCart

他の考え

カプセル化を壊すことなく他のアイテムのプライベート部分にアクセスできるため、非常に非直感的な設計ですが、Itemクラスに合計 ( ) をカウントさせることも可能です。item.calculateSum(List<Item> items)

なぜゲッターが悪いのか疑問に思っている他の人へ。getPrice()が整数を返す例を考えてみましょう。BigDecimal少なくとも、または通貨を使用したカスタムのお金の型などのより良いものに変更したい場合は、戻り値の型intが内部型を公開するため、それは不可能です。

于 2013-01-26T17:00:15.120 に答える
0

ゲッターとセッターは、カプセル化を破り、オブジェクトの内部状態を不必要に公開して、本来あるべきでない方法で変更できるようにするため、邪悪です。この問題については、次の記事で詳しく説明しています。

http://programmer.97things.oreilly.com/wiki/index.php/Encapsulate_Behavior,_not_Just_State

于 2017-03-14T15:02:40.550 に答える