java - stackoverflow - setter中文




為什麼使用getter和setter/accessors? (20)

使用getter和setter的好處是 - 只有get和set - 而不是簡單地為這些變量使用公共字段?

如果吸氣人員和安裝人員做的不僅僅是簡單的get / set,我可以很快地把這個問題弄清楚,但是我並不十分清楚:

public String foo;

比以下任何更糟糕的是

private String foo;
public void setFoo(String foo) { this.foo = foo; }
public String getFoo() { return foo; }

而前者採用的是更少的樣板代碼。


我們使用getters和setters:

  • 重用性
  • 在編程的後期階段執行驗證

Getter和setter方法是訪問私有類成員的公共接口。

封裝口頭禪

封裝咒語是為了使領域私密和方法公開。

Getter方法: 我們可以訪問私有變量。

Setter方法: 我們可以修改私人領域。

儘管getter和setter方法不會增加新的功能,但我們可以改變主意,稍後再做出該方法

  • 更好;
  • 更安全; 和
  • 更快。

在任何可以使用值的地方,都可以添加返回該值的方法。 代替:

int x = 1000 - 500

使用

int x = 1000 - class_name.getValue();

用外行人的話說

假設我們需要存儲這個Person的細節。 這個Person有領域nameagesex 。 這樣做涉及創建nameagesex 。 現在,如果我們需要創建另一個人,就必須重新創建nameagesex的方法。

我們可以用getter和setter方法創建一個bean class(Person) ,而不是這樣做。 所以,我們明天只要需要添加一個新人就可以創建這個Bean class(Person class)對象(參見圖)。 因此,我們正在重用bean類的字段和方法,這更好。


Getters and setters are used to implement two of the fundamental aspects of Object Oriented Programming which are:

  1. 抽象化
  2. Encapsulation

Suppose we have an Employee class:

package com.highmark.productConfig.types;

public class Employee {

    private String firstName;
    private String middleName;
    private String lastName;

    public String getFirstName() {
      return firstName;
    }
    public void setFirstName(String firstName) {
       this.firstName = firstName;
    }
    public String getMiddleName() {
        return middleName;
    }
    public void setMiddleName(String middleName) {
         this.middleName = middleName;
    }
    public String getLastName() {
        return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getFullName(){
        return this.getFirstName() + this.getMiddleName() +  this.getLastName();
    }
 }

Here the implementation details of Full Name is hidden from the user and is not accessible directly to the user, unlike a public attribute.


Additionally, this is to "future-proof" your class. In particular, changing from a field to a property is an ABI break, so if you do later decide that you need more logic than just "set/get the field", then you need to break ABI, which of course creates problems for anything else already compiled against your class.


Code evolves . private is great for when you need data member protection . Eventually all classes should be sort of "miniprograms" that have a well-defined interface that you can't just screw with the internals of .

That said, software development isn't about setting down that final version of the class as if you're pressing some cast iron statue on the first try. While you're working with it, code is more like clay. It evolves as you develop it and learn more about the problem domain you are solving. During development classes may interact with each other than they should (dependency you plan to factor out), merge together, or split apart. So I think the debate boils down to people not wanting to religiously write

int getVar() const { return var ; }

So you have:

doSomething( obj->getVar() ) ;

代替

doSomething( obj->var ) ;

Not only is getVar() visually noisy, it gives this illusion that gettingVar() is somehow a more complex process than it really is. How you (as the class writer) regard the sanctity of var is particularly confusing to a user of your class if it has a passthru setter -- then it looks like you're putting up these gates to "protect" something you insist is valuable, (the sanctity of var ) but yet even you concede var 's protection isn't worth much by the ability for anyone to just come in and set var to whatever value they want, without you even peeking at what they are doing.

So I program as follows (assuming an "agile" type approach -- ie when I write code not knowing exactly what it will be doing/don't have time or experience to plan an elaborate waterfall style interface set):

1) Start with all public members for basic objects with data and behavior. This is why in all my C++ "example" code you'll notice me using struct instead of class everywhere.

2) When an object's internal behavior for a data member becomes complex enough, (for example, it likes to keep an internal std::list in some kind of order), accessor type functions are written. Because I'm programming by myself, I don't always set the member private right away, but somewhere down the evolution of the class the member will be "promoted" to either protected or private .

3) Classes that are fully fleshed out and have strict rules about their internals (ie they know exactly what they are doing, and you are not to "fuck" (technical term) with its internals) are given the class designation, default private members, and only a select few members are allowed to be public .

I find this approach allows me to avoid sitting there and religiously writing getter/setters when a lot of data members get migrated out, shifted around, etc. during the early stages of a class's evolution.


From a object orientation design standpoint both alternatives can be damaging to the maintenance of the code by weakening the encapsulation of the classes. For a discussion you can look into this excellent article: http://typicalprogrammer.com/?p=23


Getter and setter methods are accessor methods, meaning that they are generally a public interface to change private class members. You use getter and setter methods to define a property. You access getter and setter methods as properties outside the class, even though you define them within the class as methods. Those properties outside the class can have a different name from the property name in the class.

There are some advantages to using getter and setter methods, such as the ability to let you create members with sophisticated functionality that you can access like properties. They also let you create read-only and write-only properties.

Even though getter and setter methods are useful, you should be careful not to overuse them because, among other issues, they can make code maintenance more difficult in certain situations. Also, they provide access to your class implementation, like public members. OOP practice discourages direct access to properties within a class.

When you write classes, you are always encouraged to make as many as possible of your instance variables private and add getter and setter methods accordingly. This is because there are several times when you may not want to let users change certain variables within your classes. For example, if you have a private static method that tracks the number of instances created for a specific class, you don't want a user to modify that counter using code. Only the constructor statement should increment that variable whenever it's called. In this situation, you might create a private instance variable and allow a getter method only for the counter variable, which means users are able to retrieve the current value only by using the getter method, and they won't be able to set new values using the setter method. Creating a getter without a setter is a simple way of making certain variables in your class read-only.


I would just like to throw the idea of annotation : @getter and @setter. With @getter, you should be able to obj = class.field but not class.field = obj. With @setter, vice versa. With @getter and @setter you should be able to do both. This would preserve encapsulation and reduce the time by not calling trivial methods at runtime.


In languages which don't support "properties" (C++, Java) or require recompilation of clients when changing fields to properties (C#), using get/set methods is easier to modify. For example, adding validation logic to a setFoo method will not require changing the public interface of a class.

In languages which support "real" properties (Python, Ruby, maybe Smalltalk?) there is no point to get/set methods.


One of the basic principals of OO design: Encapsulation!

It gives you many benefits, one of which being that you can change the implementation of the getter/setter behind the scenes but any consumer of that value will continue to work as long as the data type remains the same.


One other use (in languages that support properties) is that setters and getters can imply that an operation is non-trivial. Typically, you want to avoid doing anything that's computationally expensive in a property.


There is a good reason to consider using accessors is there is no property inheritance. See next example:

public class TestPropertyOverride {
    public static class A {
        public int i = 0;

        public void add() {
            i++;
        }

        public int getI() {
            return i;
        }
    }

    public static class B extends A {
        public int i = 2;

        @Override
        public void add() {
            i = i + 2;
        }

        @Override
        public int getI() {
            return i;
        }
    }

    public static void main(String[] args) {
        A a = new B();
        System.out.println(a.i);
        a.add();
        System.out.println(a.i);
        System.out.println(a.getI());
    }
}

輸出:

0
0
4

You should use getters and setters when:

  • You're dealing with something that is conceptually an attribute, but:
    • Your language doesn't have properties (or some similar mechanism, like Tcl's variable traces), or
    • Your language's property support isn't sufficient for this use case, or
    • Your language's (or sometimes your framework's) idiomatic conventions encourage getters or setters for this use case.

So this is very rarely a general OO question; it's a language-specific question, with different answers for different languages (and different use cases).

From an OO theory point of view, getters and setters are useless. The interface of your class is what it does, not what its state is. (If not, you've written the wrong class.) In very simple cases, where what a class does is just, eg, represent a point in rectangular coordinates,* the attributes are part of the interface; getters and setters just cloud that. But in anything but very simple cases, neither the attributes nor getters and setters are part of the interface.

Put another way: If you believe that consumers of your class shouldn't even know that you have a spam attribute, much less be able to change it willy-nilly, then giving them a set_spam method is the last thing you want to do.

* Even for that simple class, you may not necessarily want to allow setting the x and y values. If this is really a class, shouldn't it have methods like translate , rotate , etc.? If it's only a class because your language doesn't have records/structs/named tuples, then this isn't really a question of OO…

But nobody is ever doing general OO design. They're doing design, and implementation, in a specific language. And in some languages, getters and setters are far from useless.

If your language doesn't have properties, then the only way to represent something that's conceptually an attribute, but is actually computed, or validated, etc., is through getters and setters.

Even if your language does have properties, there may be cases where they're insufficient or inappropriate. For example, if you want to allow subclasses to control the semantics of an attribute, in languages without dynamic access, a subclass can't substitute a computed property for an attribute.

As for the "what if I want to change my implementation later?" question (which is repeated multiple times in different wording in both the OP's question and the accepted answer): If it really is a pure implementation change, and you started with an attribute, you can change it to a property without affecting the interface. Unless, of course, your language doesn't support that. So this is really just the same case again.

Also, it's important to follow the idioms of the language (or framework) you're using. If you write beautiful Ruby-style code in C#, any experienced C# developer other than you is going to have trouble reading it, and that's bad. Some languages have stronger cultures around their conventions than others.—and it may not be a coincidence that Java and Python, which are on opposite ends of the spectrum for how idiomatic getters are, happen to have two of the strongest cultures.

Beyond human readers, there will be libraries and tools that expect you to follow the conventions, and make your life harder if you don't. Hooking Interface Builder widgets to anything but ObjC properties, or using certain Java mocking libraries without getters, is just making your life more difficult. If the tools are important to you, don't fight them.


公共領域並不比一個getter / setter對更糟糕,除了返回字段並賦值給它外。 首先,很明顯(在大多數語言中)沒有功能差異。 任何差異必須在其他因素,如可維護性或可讀性。

getter / setter對的一個優點是,不是。 有這個說法,你可以改變實現,你的客戶不必重新編譯。 據推測,setter讓你稍後添加驗證功能,你的客戶甚至不需要知道它。 然而,向制定者添加驗證是對其先決條件的改變, 違反了先前的合同 ,這很簡單,“你可以在這裡放置任何東西,並且可以從獲得者那裡得到同樣的東西”。

所以,現在你破壞了合約,改變代碼庫中的每個文件都是你應該做的事情,而不是避免。 如果你避開它,你就會假設所有代碼都假定這些方法的合同是不同的。

如果這不應該是合同,那麼界面允許客戶將對象置於無效狀態。 這與封裝完全相反如果這個領域從一開始就不能真正被設置為任何東西,為什麼不從一開始就進行驗證呢?

這個相同的論點也適用於這些傳遞的getter / setter對的其他優點:如果您稍後決定更改設置的值,那麼您違反了合同。 如果您在派生類中重寫默認功能(超過一些無害修改(如日誌記錄或其他非可觀察行為)),那麼您將違反基類的合同。 這違反了Liskov可替代性原則,這被視為面向對象的原則之一。

如果一個班級在每個領域都有這些愚蠢的getter和setter,那麼它就是一個沒有任何不變式的班級,沒有任何合同 。 那真的是面向對象的設計嗎? 如果所有班級都有那些獲取者和設置者,那隻是一個啞數據持有者,而啞數據持有者應該看起來像啞數據持有者:

class Foo {
public:
    int DaysLeft;
    int ContestantNumber;
};

將pass-through getter / setter對添加到這樣的類不會增加任何值。 其他類應該提供有意義的操作,而不僅僅是字段已經提供的操作。 這就是你如何定義和維護有用的不變量。

客戶 :“我能用這個班級的對像做什麼?”
設計師 :“你可以讀寫幾個變量。”
客戶 :“哦,很酷,我猜?”

有理由使用getter和setter,但如果這些原因不存在,以假封裝神的名義製作getter / setter對並不是一件好事。 有效的理由使得獲得者或設置者包括經常提到的事情,因為後面可能會做出的變化,比如驗證或不同的內部表示。 或者,也許值應該是客戶可讀的,但不可寫(例如,閱讀字典的大小),所以一個簡單的getter是一個不錯的選擇。 但是當你做出選擇時,這些原因應該在那裡,而不僅僅是你以後可能想要的潛在事情。 這是YAGNI的一個例子( 你不會需要它 )。


取決於你的語言。 你已經標記了這個“面向對象”而不是“Java”,所以我想指出ChssPly76的答案是依賴於語言的。 例如,在Python中,沒有理由使用getter和setter。 如果您需要更改行為,則可以使用屬性,該屬性將基本屬性訪問的getter和setter包裝在一起。 像這樣的東西:

class Simple(object):
   def _get_value(self):
       return self._value -1

   def _set_value(self, new_value):
       self._value = new_value + 1

   def _del_value(self):
       self.old_values.append(self._value)
       del self._value

   value = property(_get_value, _set_value, _del_value)

在一個純粹的面向對象的世界中,獲取者和製定者是一個可怕的反模式 。 閱讀這篇文章: Getters / Setters。 邪惡。 期間 。 簡而言之,他們鼓勵程序員像對待數據結構一樣思考對象,而這種思維類型是純粹的程序化的(就像在COBOL或C中一樣)。 在面向對象的語言中沒有數據結構,但只有暴露行為的對象(不是屬性/屬性!)

您可以在Elegant Objects的第3.5部分(我關於面向對象編程的書)中找到更多關於它們的內容。


好吧,我只想補充一點,即使有時它們對於變量/對象的封裝和安全性是必需的,但如果我們想編寫一個真正的面向對象程序,那麼我們需要停止使用ACCESSORS ,因為有時候我們會依賴很多在他們什麼時候沒有真正需要的時候,這幾乎和我們把變量公開一樣。


很多人談論吸氣和吸氣者的優點,但我想扮演惡魔的倡導者。 現在我正在調試一個非常大的程序,程序員決定讓所有的getter和setter都做。 這看起來不錯,但它是一個逆向工程的噩夢。

假設您正在瀏覽數百行代碼,並且遇到以下情況:

person.name = "Joe";

這是一段精美的代碼,直到你意識到它是一個二傳手。 現在,你關注那個setter,並且發現它也設置了person.firstName,person.lastName,person.isHuman,person.hasReallyCommonFirstName,並且調用了person.update(),它將查詢發送到數據庫等等。哦,這就是發生內存洩漏的地方。

乍一看理解本地代碼片段是獲取者和製定者傾向於破壞的良好可讀性的重要屬性。 這就是為什麼我盡可能避免它們,並儘量減少他們在使用它們時所做的事情。


我知道這有點遲,但我認為有些人對錶演感興趣:)

我做了一點性能測試。 我寫了一個“NumberHolder”類,它擁有一個Integer。 您可以使用getter方法anInstance.getNumber()讀取該Integer,也可以使用anInstance.getNumber()直接訪問該數字。 我的程序通過兩種方式讀取數字1,000,000,000次。 該過程重複五次並打印時間。 我有以下結果:

Time 1: 953ms, Time 2: 741ms
Time 1: 655ms, Time 2: 743ms
Time 1: 656ms, Time 2: 634ms
Time 1: 637ms, Time 2: 629ms
Time 1: 633ms, Time 2: 625ms

(時間1是直接的方式,時間2是獲取者)

你看,吸氣劑(幾乎)總是快一點。 然後我嘗試了不同數量的周期。 我用了1000萬和10萬美元,而不是100萬美元。 結果:

1000萬次循環:

Time 1: 6382ms, Time 2: 6351ms
Time 1: 6363ms, Time 2: 6351ms
Time 1: 6350ms, Time 2: 6363ms
Time 1: 6353ms, Time 2: 6357ms
Time 1: 6348ms, Time 2: 6354ms

在1000萬個週期中,時間幾乎相同。 這裡有10萬(10萬)個週期:

Time 1: 77ms, Time 2: 73ms
Time 1: 94ms, Time 2: 65ms
Time 1: 67ms, Time 2: 63ms
Time 1: 65ms, Time 2: 65ms
Time 1: 66ms, Time 2: 63ms

也有不同數量的周期,吸氣劑比常規方式快一點。 我希望這對你有所幫助! :)

順便說一句,我是德語七年級的學生,使用我自己的知識和Google翻譯。 所以,不要對我的英語那麼嚴格;)


有很多原因。 我最喜歡的是當你需要改變行為或規定你可以在變量上設置什麼。 例如,假設你有一個setSpeed(int speed)方法。 但是你希望你只能設置100的最大速度。你可以這樣做:

public void setSpeed(int speed) {
  if ( speed > 100 ) {
    this.speed = 100;
  } else {
    this.speed = speed;
  }
}

現在,如果您的代碼中的任何地方使用公共領域,然後您意識到您需要上述要求,該怎麼辦? 盡情享受公共領域的每一次使用,而不僅僅是修改你的二傳手。

我的2美分:)


訪問器和增變器的一個優點是可以執行驗證。

例如,如果foo是公開的,我可以很容易地將它設置為null ,然後其他人可以嘗試調用該對象的方法。 但它不再存在! 使用setFoo方法,我可以確保foo從未設置為null

訪問器和增變器也允許封裝 - 如果你不應該看到它的值(也許它在構造函數中設置,然後被方法使用,但從未被改變),那麼它就不會被任何人看到。 但是,如果您可以允許其他類查看或更改它,則可以提供正確的存取器和/或增變器。





abstraction