web-dev-qa-db-ja.com

クラスのメソッドは独自のゲッターとセッターを呼び出す必要がありますか?

私が働いている場所には、次のようなことをするクラスがたくさんあります。

_public class ClassThatCallsItsOwnGettersAndSetters {

    private String field;

    public String getField() {
        return field;
    }

    public void setField(String field) {
        this.field = field;
    }

    public void methodWithLogic() {
        setField("value");
        //do stuff
        String localField = getField();
        //do stuff with "localField"
    }
}
_

これを最初から作成した場合、代わりにmethodWithLogic()を次のように作成します。

_public class ClassThatUsesItsOwnFields {

    private String field;

    public String getField() {
        return field;
    }

    public void setField(String field) {
        this.field = field;
    }

    public void methodWithLogic() {
        field = "value";
        //do stuff            
        //do stuff with "field"
    }
}
_

クラスが独自のゲッターとセッターを呼び出すと、コードが読みにくくなります。私にとってそれはほとんどimpliesそのメソッド呼び出しで複雑なロジックが発生していることは、私たちのケースではほとんど発生していません。見慣れないコードをデバッグしているとき、そのバグはそのメソッドの副作用ではないと誰が言うのですか?言い換えると、コードを理解するために多くの副業が必要になります。

最初の方法にメリットはありますか?最初の方法は実際に優れていますか?

53
Daniel Kaplan

どちらが良いか悪いかは言いません、それは部分的にはあなたの状況に依存するからです(私の意見では)。ただし、ゲッターとセッターは後で実装を変更する可能性があり、それらをバイパスするとそのロジックはスキップされることを考慮してください。

たとえば、後でいくつかのセッターフィールドに「ダーティ」フラグを追加するとどうなりますか?内部コードでセッターを呼び出すことにより、他のコードを変更せずにダーティフラグを設定できます。多くの場合、これは良いことです。

46
Matt S

セッターを直接呼び出すこと自体は問題ではありません。問題は本当にあるべきです:なぜ私たちのコードはどこにでもセッターを持っているのですか?

可変クラスは危険なゲームです。特に、クラス自体が独自の状態を管理している場合にそうです。それらのセッターが実際にいくつ存在する必要があるかを検討してください。コンストラクタに何個設定して、クラス自体で完全にカプセル化できるか。

フィールドを外部から設定可能にする必要がある場合は、ロジックを持つメソッドが存在するかどうかを確認してください。あなたのクラス自体は本当にデータ/状態クラスですか?このクラスには複数の責任がありますか?

誤解しないでください。これで問題ない場合もあります。ロジックを持つクラスのセッターを完全に排除するべきだと言っているのではありません。しかし、これらは例外ではなく、規則であるべきです。そして、それらのいくつかのケースでは、直接アクセスするべきものは明らかであるはずです。

33
pdr

はい、クラスのメソッドはゲッターとセッターを呼び出す必要があります。ゲッターとセッターを書く際の要点は、将来の証明です。すべてのプロパティをフィールドにして、データをクラスのユーザーに直接公開できます。ゲッターとセッターを作成する理由は、必ずしも複雑なロジックが存在するからではなく、追加する必要がある場合にインターフェースが将来壊れないためです。

9
Michael

一言であなたの質問に答えるために、はい。

クラスに独自のゲッターとセッターを呼び出させると、拡張性が増し、将来のコードのベースが改善されます。

次のようなものがあるとします。

public class Vehicle
{
    private int year;
    private String make;

    public Vehicle(int year, String make)
    {
        setYear(year);
        setMake(make);
    }

    public void setYear(int year)
    {
        this.year = year;
    }

    public void setMake(String make)
    {
        this.make = make;
    }
}

Yearとmakeのセッターを呼び出しても、機能が追加されない場合がありますが、入力検証などをセッターに追加したい場合はどうでしょうか。

public class Vehicle
{
    private int year;
    private String make;

    public Vehicle(int year, String make)
    {
        setYear(year);
        setMake(make);
    }

    public void setYear(int year)
    {
        if(year > 0)
        {
            this.year = year;
        }
        else
        {
            System.out.println(year + " is not a valid year!");
        }
    }

    public void setMake(String make)
    {
        this.make = make;
    }
}
6
Zach Latta

言及されていないことの1つは、ゲッターとセッター(すべてのメソッドとして)がJavaでは仮想であることです。これにより、コードで常にそれらを使用する別の機能が追加されます。別のユーザーがクラスを拡張し、ゲッターとセッターを上書きする可能性があります。基本クラスは、独自のデータではなく、サブクラスのデータを使用します。仮想関数を明示的にマークする言語では、これを使用して実行できる関数を予測および宣言できるため、これははるかに便利です。 Javaでは、これを常に認識しておく必要があります。それが望ましい動作である場合は、コードでそれらを使用することをお勧めします。

5
Jonathan Henson

公開インターフェースによって提供される何かを達成しようとしている場合は、getter/setterを使用します。

ただし、クラスの所有者/開発者は、コードのプライベートセクションに(もちろんクラス内から)アクセスできますが、危険を軽減する責任もあります。

したがって、内部リストを反復処理するゲッターがあり、イテレーターをインクリメントせずに現在の値を取得したい場合があります。この場合、プライベート変数を使用します。

public class MyClass
{
    private int i;
    private List<string> list;
    public string getNextString()
    {
        i++;
        return list[i];
    }

    private void getString()
    {
        // Do not increment
        string currentString = list[i];

        // Increment
        string nextString = getNextString();
    }
}
3
ConditionRacer

いいえ。

ゲッター/セッターが取得して設定するだけの場合(遅延初期化なし、チェックなしなど)、変数を使用します。将来的にゲッター/セッターを変更する場合、methodWithLogic()を変更することができ(クラスが変更されるため)、直接割り当ての代わりにゲッター/セッターを呼び出すことができます。ゲッター/セッターのこの呼び出しを文書化できます(クラスコードの残りの部分が変数を直接使用しているときにゲッター/セッターを呼び出すのはおかしいので)。

JVMはゲッター/セッターへの頻繁な呼び出しをインライン化します。したがって、パフォーマンスの問題になることはありません。変数を使用する利点は、読みやすさと私見です。

お役に立てれば..

1
Pravin Sonawane

はい。ゲッターとセッターは状態を表すので、この質問を裏返します。必要がない限り、同じ方法でオブジェクトの状態を変更する複数の方法を追跡する必要がありますか?

追跡する必要のあるものが少なくなればなるほど、不変オブジェクトの処理が容易になります。

パブリックフィールドとパブリックゲッター/セッターの両方を持つことを妨げるものは何もないことを考慮してください。

場合によっては望ましいであるか、1つ以上の理由でフィールドに直接アクセスする必要があるかもしれませんが、発生した場合でもそれを避けてはいけません。しかし、そうすることによる明確なメリットがある場合にのみ、実際にそれを行うべきです。

1
jmoreno

どちらの方法にも使用例があります。パブリックセッターはフィールド値(および/またはバインドされた値)の整合性を保つため、メソッドロジックがこの整合性ロジックに干渉しない場合は、セッターを使用する必要があります。 「プロパティ」を設定するだけの場合は、セッターを使用します。一方、重いセッターを使用したバルク操作や、セッターの概念が単純すぎる操作など、一部のフィールドに直接アクセスする必要がある場合があります。

一貫性を保つのはあなたの責任です。セッターは定義によりこれを行いますが、複雑なケースはカバーできません。

1
Artur