เมื่อ Getters และ Setters เป็นธรรม


175

Getters และ setters มักถูกวิพากษ์วิจารณ์ว่าไม่เหมาะสม OO ในทางกลับกันรหัส OO ส่วนใหญ่ที่ฉันเคยเห็นมีตัวรับมากมายและตัวตั้งค่า

เมื่อ getters และ setters เป็นธรรม? คุณพยายามหลีกเลี่ยงการใช้งานหรือไม่ โดยทั่วไปแล้วพวกเขาใช้มากเกินไปหรือไม่?

หากภาษาที่คุณชื่นชอบมีคุณสมบัติ (ของฉัน) แล้วสิ่งเหล่านี้จะถือว่าเป็นผู้ได้รับและผู้ตั้งค่าสำหรับคำถามนี้ พวกเขาเป็นสิ่งเดียวกันจากมุมมองวิธีการ OO พวกเขามีไวยากรณ์ที่ดีกว่า

แหล่งที่มาสำหรับการวิจารณ์ Getter / Setter (บางคนนำมาจากความคิดเห็นเพื่อให้พวกเขามองเห็นได้ดีขึ้น):

ในการระบุคำวิจารณ์อย่างง่าย ๆ : Getters and Setters อนุญาตให้คุณจัดการสถานะภายในของวัตถุจากด้านนอกของวัตถุ นี่เป็นการละเมิด encapsulation เฉพาะวัตถุเท่านั้นที่ควรดูแลเกี่ยวกับสถานะภายในของมัน

และตัวอย่างรหัสขั้นตอน

struct Fridge
{
    int cheese;
}

void go_shopping(Fridge fridge)
{
     fridge.cheese += 5;
}

โค้ดเวอร์ชัน Mutator:

class Fridge
{
     int cheese;

     void set_cheese(int _cheese) { cheese = _cheese; }
     int get_cheese() { return cheese; }
 }

void go_shopping(Fridge fridge)
{
     fridge.set_cheese(fridge.get_cheese() + 5);        
}

getters และ setters ทำให้โค้ดมีความซับซ้อนมากขึ้นโดยไม่ต้องมีการห่อหุ้มที่เหมาะสม เนื่องจากสถานะภายในสามารถเข้าถึงวัตถุอื่น ๆ เราไม่ได้รับมากทั้งโดยการเพิ่ม getters และ setters เหล่านี้

ก่อนหน้านี้คำถามถูกพูดถึงใน Stack Overflow:


21
Getters and setters are often criticized as being not proper OO- การอ้างอิงโปรด
Robert Harvey


45
@ งานทำไมเพราะมันมีรหัส? มันเป็นคำถามที่ดีและก่อให้เกิดสงครามศักดิ์สิทธิ์หากถือเอาจริงเอาจัง
Peter Turner

2
@Winston Ewert: "... คำถามคือถ้าคุณควรจะเข้าถึงข้อมูลในชั้นเรียนเลย": ไม่มีใครบังคับให้คุณใช้ getters และ setters สำหรับตัวแปรสมาชิกทั้งหมดคุณใช้สิ่งที่คุณต้องการเท่านั้น นั่นเป็นเหตุผลที่คุณใช้ getters และ setters แทนตัวแปรสมาชิกสาธารณะ
Giorgio

2
@Winston Ewert: ฉันไม่เห็นว่าการขาดตัวรับ / ผู้ตั้งค่าจะแก้ปัญหานี้ได้อย่างไร: ต้องมีวิธีในการเข้าถึงข้อมูลทุกส่วนไม่เช่นนั้นจะไร้ประโยชน์ มันเป็นหน้าที่ของการออกแบบที่ดีในการตัดสินใจว่าส่วนใดของข้อมูลที่สามารถเข้าถึงได้ซึ่งเป็นส่วนหนึ่งของรหัส ถ้าใครเป็นนักออกแบบที่ไม่ดีเขาหรือเธอจะเป็นเช่นนั้นด้วยหรือไม่ได้รับและ setters แค่ 2 เซ็นต์ของฉัน
Giorgio

คำตอบ:


162

การมี getters และ setters ไม่ได้ทำให้ encapsulation ขาดตัวเอง สิ่งที่ทำให้ encapsulation หยุดพักคือการเพิ่มตัวรับและตัวตั้งค่าให้กับสมาชิกข้อมูลทุกคน (ทุกฟิลด์ในภาษาจาวาลิง) โดยไม่คิดอะไรเลย แม้ว่าสิ่งนี้จะดีกว่าการทำให้ข้อมูลทั้งหมดเป็นข้อมูลสาธารณะ แต่เพียงไม่กี่ก้าว

จุดของการห่อหุ้มไม่ใช่ว่าคุณไม่ควรรู้หรือเปลี่ยนแปลงสถานะของวัตถุจากภายนอกวัตถุ แต่คุณควรมีนโยบายที่สมเหตุสมผลในการทำเช่นนั้น

  • สมาชิกข้อมูลบางคนอาจอยู่ภายในวัตถุทั้งหมดและไม่ควรมีผู้ได้รับหรือผู้ตั้งค่า

  • ข้อมูลสมาชิกบางคนควรเป็นแบบอ่านอย่างเดียวดังนั้นพวกเขาอาจต้องการ getters แต่ไม่ใช่ setters

  • ข้อมูลสมาชิกบางคนอาจต้องรักษาให้สอดคล้องกัน ในกรณีเช่นนี้คุณจะไม่ให้ผู้ตั้งค่าสำหรับแต่ละคน แต่เป็นวิธีการเดียวในการตั้งค่าในเวลาเดียวกันเพื่อให้คุณสามารถตรวจสอบค่าเพื่อความมั่นคง

  • ข้อมูลสมาชิกบางคนอาจจำเป็นต้องเปลี่ยนแปลงในวิธีที่แน่นอนเช่นเพิ่มหรือลดจำนวนคงที่ ในกรณีนี้คุณจะต้องให้increment()และ / หรือdecrement()วิธีการมากกว่า setter

  • แต่คนอื่นอาจจำเป็นต้องอ่าน - เขียนและมีทั้งผู้ทะเยอทะยานและผู้ตั้งตน

class Personลองพิจารณาจากตัวอย่างหนึ่ง สมมติว่าบุคคลนั้นมีชื่อหมายเลขประกันสังคมและอายุ สมมติว่าเราไม่อนุญาตให้ผู้คนเปลี่ยนชื่อหรือหมายเลขประกันสังคม อย่างไรก็ตามอายุของบุคคลนั้นควรเพิ่มขึ้น 1 ปีทุก ๆ ปี ในกรณีนี้คุณจะต้องสร้างนวตกรรมที่จะเริ่มต้นชื่อและ SSN ให้กับค่าที่กำหนดและซึ่งจะเริ่มต้นอายุ 0 คุณยังมีวิธีการincrementAge()ซึ่งจะเพิ่มอายุโดย 1 คุณจะให้ ทะเยอทะยานสำหรับทั้งสาม ไม่จำเป็นต้องใช้ตัวตั้งค่าในกรณีนี้

ในการออกแบบนี้คุณอนุญาตให้ตรวจสอบสถานะของวัตถุจากนอกชั้นเรียนและคุณอนุญาตให้เปลี่ยนจากนอกชั้นเรียน อย่างไรก็ตามคุณไม่อนุญาตให้มีการเปลี่ยนแปลงสถานะโดยพลการ มีนโยบายซึ่งระบุว่าชื่อและ SSN ไม่สามารถเปลี่ยนแปลงได้อย่างมีประสิทธิภาพและอายุสามารถเพิ่มได้ครั้งละ 1 ปี

ตอนนี้สมมติว่าคน ๆ หนึ่งมีเงินเดือนเช่นกัน และผู้คนสามารถเปลี่ยนงานได้ตามต้องการซึ่งหมายความว่าเงินเดือนของพวกเขาจะเปลี่ยนไปด้วย เพื่อจำลองสถานการณ์นี้เราไม่มีวิธีอื่นนอกจากให้setSalary()วิธี! การอนุญาตให้มีการเปลี่ยนแปลงเงินเดือนที่จะเป็นนโยบายที่เหมาะสมอย่างสมบูรณ์ในกรณีนี้

โดยวิธีการในตัวอย่างของคุณ, ฉันจะให้ชั้นและวิธีการแทนและ จากนั้นคุณจะยังคงมีการห่อหุ้มFridgeputCheese()takeCheese()get_cheese()set_cheese()


public class Fridge {
  private List objects;
  private Date warranty;

  /** How the warranty is stored internally is a detail. */
  public Fridge( Date warranty ) {
    // The Fridge can set its internal warranty, but it is not re-exposed.
    setWarranty( warranty );
  }

  /** Doesn't expose how the fridge knows it is empty. */
  public boolean isEmpty() {
    return getObjects().isEmpty();
  }

  /** When the fridge has no more room... */
  public boolean isFull() {
  }

  /** Answers whether the given object will fit. */
  public boolean canStore( Object o ) {
    boolean result = false;

    // Clients may not ask how much room remains in the fridge.
    if( o instanceof PhysicalObject ) {
      PhysicalObject po = (PhysicalObject)o;

      // How the fridge determines its remaining usable volume is a detail.
      // How a physical object determines whether it fits within a specified
      // volume is also a detail.
      result = po.isEnclosedBy( getUsableVolume() );
    }

     return result;
  }

  /** Doesn't expose how the fridge knows its warranty has expired. */
  public boolean isPastWarranty() {
    return getWarranty().before( new Date() );
  }

  /** Doesn't expose how objects are stored in the fridge. */
  public synchronized void store( Object o ) {
    validateExpiration( o );

    // Can the object fit?
    if( canStore( o ) ) {
      getObjects().add( o );
    }
    else {
      throw FridgeFullException( o );
    }
  }

  /** Doesn't expose how objects are removed from the fridge. */
  public synchronized void remove( Object o ) {
    if( !getObjects().contains( o ) ) {
      throw new ObjectNotFoundException( o );
    }

    getObjects().remove( o );

    validateExpiration( o );
  }

  /** Lazily initialized list, an implementation detail. */
  private synchronized List getObjects() {
    if( this.list == null ) { this.list = new List(); }
    return this.list;
  }

  /** How object expiration is determined is also a detail. */
  private void validateExpiration( Object o ) {
    // Objects can answer whether they have gone past a given
    // expiration date. How each object "knows" it has expired
    // is a detail. The Fridge might use a scanner and
    // items might have embedded RFID chips. It's a detail hidden
    // by proper encapsulation.
    if( o implements Expires && ((Expires)o).expiresBefore( today ) ) {
      throw new ExpiredObjectException( o );
    }
  }

  /** This creates a copy of the warranty for immutability purposes. */
  private void setWarranty( Date warranty ) {
    assert warranty != null;
    this.warranty = new Date( warranty.getTime() )
  }
}

4
โปรดอย่าใช้ตัวอย่างของฉันในตู้เย็นอย่างจริงจังเกินไป :) ตู้เย็นจริงควรเป็นวัตถุที่บรรจุฉันคาดหวังว่าจะรู้วิธีการเก็บวัตถุโดยไม่ต้องกังวลเกี่ยวกับสิ่งที่พวกเขาเป็น IE มันจะเหมือน ArrayList สำหรับสิ่งที่ทำให้มันเป็นตู้เย็นสมมติว่ามันเป็นอันดับวัตถุไปยังดิสก์เมื่อเก็บไว้เพื่อให้พวกเขาจะรอดจากความล้มเหลวของระบบ ตกลง. ยกตัวอย่างตู้เย็นของฉันให้จริงจัง
Winston Ewert

6
แต่ตู้เย็นไม่ควรรู้วันหมดอายุดังนั้นจึงสามารถบอกคุณได้ว่าชีสแย่มากและควรถูกโยนทิ้ง :) ตกลงเราต้องหยุดสิ่งนี้! :)
Dima

10
การพูดคุยที่น่าสนใจเกี่ยวกับFridge Logic ที่น่าสนใจที่คุณเกิดขึ้นที่นี่ ...
Mason Wheeler

35
ฮ่าฮ่าฉันอยากเห็นโฆษณานี้: "มันเป็นตู้เย็นแบบใหม่: มันโยนสิ่งต่าง ๆ มาที่คุณเมื่อพยายามจะคว้าอะไรบางอย่างที่ไม่ได้อยู่ในนั้นด้วยวิธีนี้คุณจะลองครั้งเดียว! คุณกังวลเกี่ยวกับ บรรจุตู้เย็นและปล่อยให้ตู้เย็นกังวลเกี่ยวกับพฤติกรรมที่ผิดกฎหมาย! "
gablin

42
ตัวอย่างมันผิดทั้งหมด ไม่ควรมีฟิลด์ Age หรือเมธอด setAge () Age เป็นฟังก์ชันของ Person birthDate เมื่อเปรียบเทียบกับบางช่วงเวลา ในขณะที่ดูไม่สำคัญนี่เป็นสิ่งที่ผิดกับการปฏิบัติที่ทันสมัยของการเปลี่ยนแปลงที่ไม่สมบูรณ์ของวัตถุและการออกแบบที่ไม่ดีอื่น ๆ ตามที่เห็นโดยวิธีการรับ / ตั้งค่าสำหรับเขตข้อมูลส่วนตัวเมื่อเทียบกับการพิจารณาอย่างระมัดระวัง ควรทราบเกี่ยวกับพฤติกรรมของมันและการเปลี่ยนแปลงสถานะใดบ้างที่ใช้ได้จริง (วิธีการ setX ใดทำลายอย่างสมบูรณ์)
Darrell Teague

41

เหตุผลพื้นฐานสำหรับ getters และ setters ใน Java นั้นง่ายมาก:

  • คุณสามารถระบุได้เฉพาะวิธีการไม่ใช่สาขาในส่วนต่อประสาน

ดังนั้นหากคุณต้องการอนุญาตให้ฟิลด์ส่งผ่านอินเทอร์เฟซคุณจะต้องใช้เครื่องอ่านและวิธีการเขียน สิ่งเหล่านี้เรียกว่า getX และ setX สำหรับฟิลด์ x


44
นั่นเป็นข้อ จำกัด ทางภาษา คำถามจริงคือเราควรอนุญาตให้วัตถุอื่นจัดการกับสถานะนั้นหรือไม่
Winston Ewert

3
@Peter Turner ไม่มีอะไรจะป้องกันภาษาจากการมีส่วนต่อประสานที่มีคุณสมบัติ ภายใต้หน้าปกที่อาจนำไปใช้เป็น getter / setter ได้ แต่มันจะง่ายพอที่จะเพิ่มการสนับสนุนให้กับนิยามของอินเตอร์เฟสสำหรับคุณสมบัติ
Winston Ewert

2
@Winston ในที่สุดคุณจะต้องอนุญาตให้ชั้นเรียนส่งผ่านข้อมูลไปมาระหว่างกันเพื่อให้งานสำเร็จลุล่วง คุณจะแนะนำอะไรแทน

6
วัตถุควรจะให้อินเทอร์เฟซระดับที่สูงขึ้นเพื่ออวัยวะภายใน Getters และ Setters มีแนวโน้มที่จะเป็นอินเทอร์เฟซระดับต่ำ ตัวอย่างเช่นสมมติว่าคุณมีคลาสที่ใช้ต้นไม้ไบนารี คุณสามารถมีฟังก์ชั่นเช่น GetLeft (), GetRight (), GetValue () และ GetKey () เพื่อนำทางต้นไม้ แต่นั่นเป็นวิธีการที่ผิดอย่างสมบูรณ์ คลาสต้นไม้ไบนารีของคุณควรมีการดำเนินการเช่นค้นหาแทรกลบ
Winston Ewert

6
หากต้องการยกตัวอย่างอื่นพิจารณาชิ้นส่วน tetris ชิ้นส่วน tetris มีสถานะภายในบางอย่างเช่น block_type, การหมุน, ตำแหน่ง คุณสามารถมี getters เช่น GetBlockType (), GetRotation (), GetPosition () แต่คุณไม่ควรทำ สิ่งที่คุณควรมีคือวิธี GetSquares () ซึ่งส่งกลับรายการของสี่เหลี่ยมทั้งหมดที่ครอบครองโดยชิ้นนี้ คุณไม่ควรมีสิ่งต่าง ๆ เช่น SetPosition () หรือ SetRotation () แต่คุณควรมีการดำเนินการเช่น MoveLeft (), MoveRight (), Rotate (), Fall ()
Winston Ewert

20

จากhttp://www.adam-bien.com/roller/abien/entry/encapsulation_violation_with_getters_and

สไตล์ JavaBean:

connection.setUser("dukie");
connection.setPwd("duke");
connection.initialize();

OO สไตล์:

connection.connect("dukie","duke");

เห็นได้ชัดว่าฉันชอบวิธีการหลัง มันไม่ทำให้รายละเอียดการใช้งานราบรื่นและรัดกุมยิ่งขึ้นและข้อมูลที่จำเป็นทั้งหมดนั้นรวมอยู่ในการเรียกใช้เมธอดดังนั้นจึงง่ายต่อการทำให้ถูกต้อง ฉันยังต้องการตั้งค่าสมาชิกส่วนตัวโดยใช้พารามิเตอร์ในตัวสร้างเมื่อเป็นไปได้

คำถามของคุณคือเมื่อเป็นผู้ตัดสินทะเยอทะยาน / setter? บางทีเมื่อจำเป็นต้องเปลี่ยนโหมดหรือคุณต้องการสอบถามวัตถุสำหรับข้อมูลบางอย่าง

myObject.GetStatus();
myObject.SomeCapabilitySwitch = true;

ในการคิดเกี่ยวกับมันเมื่อฉันเริ่มเขียนโค้ดใน C # เป็นครั้งแรกฉันเขียนโค้ดจำนวนมากในสไตล์ Javabeans ที่แสดงไว้ด้านบน แต่เมื่อฉันได้รับประสบการณ์ทางภาษาฉันก็เริ่มสร้างสมาชิกในคอนสตรัคเตอร์มากขึ้นและใช้วิธีการที่ดูเหมือนสไตล์ OO ด้านบน


6
เหตุใด "ให้อาร์กิวเมนต์ทั้งหมดเป็นพารามิเตอร์" OO-style

5
ในขณะที่ "OO-style" ของคุณใช้ได้ดีสำหรับตัวเลือก 2 หรือ 3 ตัวฉันจะชอบสไตล์ JavaBean เมื่อคุณเหนือกว่านั้น มี 20 วิธีมากไปสำหรับการรวมกันของพารามิเตอร์ที่เป็นไปได้ทั้งหมดดูน่ากลัว
TheLQ

1
@TheLQ: C # 4.0 ช่วยให้ง่ายขึ้นโดยอนุญาตพารามิเตอร์ทางเลือกและชื่อในตัวสร้างและการเรียกเมธอด
Robert Harvey

7
@TheLQ นั่นคือสิ่งที่สร้างด้วยไวยากรณ์คล่องสำหรับการดูเช่นMapMaker ฝรั่งของ
maaartinus

5
@ Thorbjørn Ravn Andersen ฉันจะพูดว่า "ให้อาร์กิวเมนต์ทั้งหมดเป็นพารามิเตอร์" ดีกว่า OO สไตล์กว่า "call set JavaBean" เพราะ setter หมายถึงมีคุณลักษณะพื้นฐานที่ถูกตั้งค่าซึ่งโดยนิยามจะเปิดเผยรายละเอียดภายใน การใช้เมธอด connect (.. ) ในตัวอย่างทำให้ไม่มีข้อสมมติเช่นนั้น บางทีคุณอาจตั้งค่าแอตทริบิวต์ผู้ใช้และรหัสผ่านบางทีคุณอาจไม่ สิ่งสำคัญคือคุณต้องมุ่งเน้นที่แนวคิด OO ที่เหมาะสมนั่นคือข้อความ "เชื่อมต่อ"
Andres F.

13

เมื่อ getters และ setters เป็นธรรม?

เมื่อพฤติกรรม "รับ" และ "ตั้งค่า" ตรงกับพฤติกรรมในแบบจำลองของคุณซึ่งไม่เคยมีมาก่อน

การใช้งานอื่น ๆ ทั้งหมดเป็นเพียงการโกงเพราะพฤติกรรมของโดเมนธุรกิจไม่ชัดเจน

แก้ไข

คำตอบนั้นอาจจะดูลื่นไหลดังนั้นขอผมขยายหน่อย คำตอบข้างต้นส่วนใหญ่ถูกต้อง แต่มุ่งเน้นไปที่กระบวนทัศน์การเขียนโปรแกรมของการออกแบบ OO และบางสิ่งที่พลาดภาพใหญ่ จากประสบการณ์ของฉันสิ่งนี้ทำให้ผู้คนคิดว่าการหลีกเลี่ยง gettings และ setters เป็นกฎทางวิชาการสำหรับภาษาการเขียนโปรแกรม OO (เช่นคนคิดว่าการแทนที่ getters ด้วยคุณสมบัติเป็นสิ่งที่ยิ่งใหญ่)

ในความเป็นจริงมันเป็นผลมาจากกระบวนการออกแบบ คุณไม่จำเป็นต้องเข้าสู่ส่วนต่อประสานและการห่อหุ้มและรูปแบบโดยพิจารณาว่ามันทำหรือไม่ทำลายกระบวนทัศน์เหล่านี้และอะไรคือหรือไม่ดีในการเขียนโปรแกรม OO จุดเดียวที่ในที่สุดมีความสำคัญก็คือหากไม่มีสิ่งใดในโดเมนของคุณที่ใช้งานได้เช่นนี้โดยการใส่ไว้ในคุณไม่ได้เป็นแบบจำลองโดเมนของคุณ

ความจริงก็คือมันไม่น่าเป็นไปได้สูงที่ระบบใด ๆ ในพื้นที่โดเมนของคุณจะมีตัวรับและตัวตั้งค่า คุณไม่สามารถเดินขึ้นไปชายหรือหญิงที่เป็นผู้รับผิดชอบในการจ่ายเงินเดือนและก็พูดว่า"ตั้งเงินเดือนนี้ X"หรือ"รับเงินเดือนฉันคนนี้" พฤติกรรมดังกล่าวไม่มีอยู่จริง

หากคุณใส่สิ่งนี้ลงในรหัสของคุณคุณไม่ได้ออกแบบระบบของคุณเพื่อให้ตรงกับรูปแบบของโดเมนของคุณ ใช่ว่าจะทำลายส่วนต่อประสานและการห่อหุ้ม แต่นั่นไม่ใช่ประเด็น ประเด็นก็คือคุณกำลังสร้างโมเดลสิ่งที่ไม่มีอยู่

ยิ่งกว่านั้นคุณอาจพลาดขั้นตอนหรือกระบวนการสำคัญเนื่องจากอาจมีเหตุผลที่ฉันไม่สามารถเดินขึ้นไปจ่ายเงินเดือนและบอกให้ตั้งเงินเดือนเป็น X

เมื่อผู้คนใช้ผู้บุกรุกและผู้ตั้งค่าพวกเขามักจะผลักดันกฎสำหรับกระบวนการนี้ไปในที่ที่ไม่ถูกต้อง สิ่งนี้กำลังเคลื่อนห่างจากโดเมนของคุณมากยิ่งขึ้น ใช้ตัวอย่างของโลกแห่งความจริงมันเหมือนกับเงินเดือนที่สมมติว่าคนที่เดินเข้ามามีสิทธิ์ได้รับค่าเหล่านี้มิฉะนั้นเขาจะไม่ขอพวกเขา ไม่เพียงเท่านั้นไม่ใช่ว่าโดเมนจะเป็นอย่างไร แต่เป็นเรื่องโกหกว่าโดเมนเป็นอย่างไร


สิ่งนี้ดูเหมือนจะไม่นำเสนออะไรมากมายเกินกว่าที่ทำคะแนนและอธิบายไว้ในคำตอบก่อนหน้า 17 คำตอบ
gnat

1
คำตอบอื่น ๆ พูดถึงวัตถุอินเทอร์เฟซและกระบวนทัศน์ภาษาอื่น ๆ ซึ่งเป็นเรื่องดี แต่ก็ไม่ใช่ประเด็นสำคัญ เก็ตเตอร์และเซ็ตเตอร์ไม่ได้เลวร้ายเพียงเพราะพวกเขาทำผิดระเบียบการเขียนโค้ด แต่ส่วนใหญ่เป็นเพราะคุณแทบจะไม่เคยพบกับพฤติกรรมนี้ในรูปแบบที่แท้จริงที่คุณเป็นตัวแทนอยู่ จุดนี้มีแนวโน้มที่จะหายไปในการสนทนาเกี่ยวกับวิธีปฏิบัติที่ดีที่สุดในการเข้ารหัส
Cormac Mulhall

คุณคิดว่าส่วนต่อประสานการจ่ายเงินเดือนคืออะไรหากไม่ใช่set/getเงินเดือน?
Winston Ewert

1
หากพวกเขาถูกห่อหุ้มเลเยอร์การอนุญาตและ จำกัด เฉพาะหน่วยงานภายนอกบางอย่างพวกเขาไม่ใช่ผู้ได้รับและผู้ตั้ง ฉันไม่ได้บอกว่าไม่มีวิธีการใด ๆ ในแผนกบัญชีเงินเดือนที่เปลี่ยนเงินเดือน แต่วิธีนั้นควรสอดคล้องกับกระบวนการภายในที่เกิดขึ้นใน บริษัท เอง ตัวอย่างเช่น บริษัท ส่วนใหญ่กำหนดเงินเดือนตามสัญญาของพนักงานซึ่งได้รับอนุญาตจากผู้จัดการ หากเงินเดือนของพนักงานเปลี่ยนแปลงสัญญาใหม่จะถูกดึงขึ้นมาและผู้จัดการต้องลงชื่อ ดังนั้นเงินเดือนควรคาดหวังวัตถุสัญญาและวัตถุการอนุญาตบางอย่างเพื่อเปลี่ยนม้วนจ่าย
Cormac Mulhall

3
หรือพูดอีกอย่างหนึ่งก็คือความแตกต่างระหว่าง set_salary (new_salary, employee_id) และ authorized_salary_update (employee_contract, authorising_manager) กระบวนการควรเป็นแบบจำลองกระบวนการทางธุรกิจภายใน
Cormac Mulhall

11

ตามกฎทั่วไปผู้ได้รับและผู้ตั้งเป็นแนวคิดที่ไม่ดี หากฟิลด์ไม่ได้เป็นส่วนหนึ่งของส่วนต่อประสานแบบมีเหตุผลและคุณทำให้เป็นแบบส่วนตัวนั่นก็ใช้ได้ หากเป็นส่วนหนึ่งของส่วนต่อประสานแบบมีเหตุมีผลและคุณทำให้เป็นสาธารณะก็ไม่เป็นไร แต่ถ้าคุณทำให้มันเป็นส่วนตัวแล้วหันหลังให้เป็นสาธารณะอีกครั้งอย่างมีประสิทธิภาพด้วยการให้ทะเยอทะยานและสุนัขเซทเทอร์คุณจะกลับไปที่จุดเริ่มต้นของคุณ

เห็นได้ชัดว่ามีข้อยกเว้น ใน Java คุณอาจต้องใช้อินเตอร์เฟส ไลบรารีมาตรฐาน Java มีข้อกำหนดด้านความเข้ากันได้แบบย้อนหลังอย่างมากซึ่งเกินความจำเป็นในการวัดคุณภาพของรหัสปกติ อาจเป็นไปได้ว่าคุณอาจต้องจัดการกับตำนาน แต่เป็นกรณีที่หายากซึ่งมีโอกาสที่ดีที่คุณจะสามารถแทนที่ฟิลด์ที่เก็บไว้ด้วยการคำนวณแบบทันทีโดยไม่ต้องทำลายอินเตอร์เฟส แต่สิ่งเหล่านี้เป็นข้อยกเว้น Getters และ setters เป็นรูปแบบการต่อต้านที่ต้องการเหตุผลพิเศษ


6
getter และ setter หมายความว่าแอ็ตทริบิวต์ไม่ใช่ฟิลด์เป็นส่วนหนึ่งของอินเตอร์เฟส สมมติว่า getBirthDate () และ SetBirthDate () รับ "yyyy / mm / dd" แต่ฟิลด์ที่เก็บไว้คือจำนวนวันตั้งแต่ 01/01/1000 คุณสามารถเปลี่ยนเป็น 01/01/0001 และผู้ทะเยอทะยานและผู้ตั้งค่าจะทำให้อินเทอร์เฟซเหมือนเดิม โดยเฉพาะอย่างยิ่งเนื่องจาก 'สาธารณะ' หมายถึงถังขยะสาธารณะตัวแปรไม่ควรเป็นสาธารณะ ใช้ setter เพื่อตรวจสอบความถูกต้องของค่าที่ได้รับ, อัพเดททุกฟิลด์ที่เกี่ยวข้อง, แปลงตามต้องการ, ฯลฯ ลองใช้ getter ในกรณีที่หน่วยเก็บข้อมูลภายในเปลี่ยนแปลง
Andy Canfield

@AndyCanfield มันค่อนข้างแข็งแกร่งที่จะพูดในที่สาธารณะหมายถึงถังขยะสาธารณะนั่นเป็นเพียงดังนั้นถ้าคุณเขียนโปรแกรมไม่ดี หากคุณมี setter และส่งค่าที่ไม่ถูกต้องไปแล้วคุณสามารถโยนข้อยกเว้นที่คุณสามารถเรียก trashing โปรแกรม แต่มันเลิกกับข้อผิดพลาดนอกจากนี้หากผู้ใช้ของวัตถุสามารถให้ค่าตัวแปรและ cud ให้มันผิด ค่าแล้วคุณสามารถจำได้ว่าในใจและทดสอบ it.u อาจพูดว่า "อา แต่ฉันต้องทำ 1 การทดสอบถ้าฉันใช้ setter" แต่บางทีรหัสของคุณเองให้ตัวแปรที่ไม่ดี .. ดังนั้น setter อาจไม่ ลดการทดสอบของคุณด้วยการทดสอบคุณไม่ได้เป็น "ถังขยะ"
barlop

3

ไม่ว่าจะเป็นฟิลด์ที่สามารถเข้าถึงได้โดยตรงหรือผ่านวิธีการไม่สำคัญจริงๆ

ค่าคงที่คลาส (ค่าที่มีประโยชน์) เป็นสิ่งสำคัญ และเพื่อรักษาพวกเขาบางครั้งเราต้องไม่สามารถเปลี่ยนบางสิ่งจากภายนอก เช่น. ถ้าเรามีคลาสสแควร์ที่มีความกว้างและความสูงที่แยกจากกันการเปลี่ยนหนึ่งในนั้นจะทำให้มันกลายเป็นอย่างอื่นมากกว่าสแควร์ ดังนั้นเราต้องการวิธีการเปลี่ยนด้านถ้ามันเป็นสี่เหลี่ยมผืนผ้าเราอาจมีเซ็ตเตอร์ / ฟิลด์สาธารณะ แต่ตัวตั้งค่ามากกว่าจะทดสอบว่ามันมากกว่าศูนย์หรือไม่จะดีกว่า

และในภาษาที่เป็นรูปธรรม (เช่น. java) เป็นเหตุผลที่เราต้องการวิธีการเหล่านั้น (อินเทอร์เฟซ) และอีกเหตุผลหนึ่งสำหรับเมธอดคือความเข้ากันได้ (แหล่งที่มาและไบนารี) ดังนั้นง่ายต่อการเพิ่มพวกเขาแล้วคิดว่าเขตข้อมูลสาธารณะจะเพียงพอหรือไม่

BTW ฉันชอบที่จะใช้คลาสที่มีค่าไม่เปลี่ยนแปลงอย่างไม่ย่อท้อพร้อมกับฟิลด์สาธารณะสุดท้าย


นี่เป็นสิ่งเดียวที่ควรหลีกเลี่ยง การเปลี่ยนจากฟิลด์เป็นคุณสมบัติ / getter / setter เป็นการเปลี่ยนแปลงที่รุนแรงในภาษาส่วนใหญ่
MrDosu

2

คุณอาจต้องการเปลี่ยน internals ของคุณเป็นอะไรก็ได้ในขณะที่ทำให้อินเทอร์เฟซเหมือนเดิม หากอินเทอร์เฟซของคุณไม่แตกต่างกันรหัสเหล่านั้นจะไม่แตก คุณยังสามารถเปลี่ยนรูปภายในได้ตามต้องการ


1
ฉันประหลาดใจที่คำตอบนี้ลงไปมาก Getters และ setters ช่วยให้คุณสามารถทำสิ่งต่างๆได้มากขึ้นในอนาคต (เช่นดำเนินการเหตุการณ์ทำการตรวจสอบอินพุตเพิ่มเติมทำบัญชีภายใน) โดยไม่ทำลาย API ที่มีอยู่ของคุณ แม้ว่าจะใช้รหัสที่ไม่ใช่แบบสาธารณะ แต่ก็มี API ที่น้อยลงที่คุณต้องเปลี่ยนการพึ่งพาที่น้อยลงในการอัปเดต
AmadeusDrZaius

0

แนวทางของฉันคือ -

เมื่อฉันคาดหวังที่จะทำกับข้อมูลในภายหลัง, getter / setter เป็นธรรม นอกจากนี้หากมีการเปลี่ยนแปลงเกิดขึ้นฉันมักจะผลักดันข้อมูลเข้าสู่ตัวตั้งค่า / ตัวตั้งค่า

ถ้าเป็นโครงสร้าง POD ฉันจะปล่อยให้ช่องว่าง

ในระดับที่เป็นนามธรรมมากขึ้นคำถามคือ "ใครเป็นผู้จัดการข้อมูล" และขึ้นอยู่กับโครงการ


0

หากใช้ตัวรับและตัวตั้งค่ารู้สึกซับซ้อนปัญหาอาจเป็นภาษาไม่ใช่แนวคิด

นี่คือโค้ดจากตัวอย่างที่สองที่เขียนใน Ruby:

class Fridge
  attr_accessor :cheese
end

def go_shopping fridge
  fridge.cheese += 5
end

สังเกตว่ามันดูเหมือนตัวอย่างแรกใน Java ใช่ไหม เมื่อ getters และ setters ได้รับการปฏิบัติในฐานะพลเมืองชั้นหนึ่งพวกเขาไม่ได้น่าเบื่อที่จะใช้งานและบางครั้งความยืดหยุ่นที่เพิ่มขึ้นอาจเป็นประโยชน์อย่างแท้จริง - ตัวอย่างเช่นเราสามารถตัดสินใจคืนค่าเริ่มต้นสำหรับชีสบนตู้เย็นใหม่:

class Fridge
  attr_accessor :cheese

  def cheese
    @cheese || 0
  end
end

แน่นอนว่าจะมีตัวแปรมากมายที่ไม่ควรเปิดเผยต่อสาธารณะ การเปิดเผยตัวแปรภายในโดยไม่จำเป็นนั้นจะทำให้โค้ดของคุณแย่ลง แต่คุณแทบจะไม่สามารถตำหนิได้ในส่วนของ getters และ setters


นั่นคือที่ระบุไว้อย่างสวยงาม มีการเพิ่มฟังก์ชันตัวสร้างเนื่องจากเราต้องการสร้างวัตถุที่ไม่เปลี่ยนรูปแบบในขณะที่ค่อยๆสร้างสูตร: บางทีถ้าคุณเพิ่มสารให้ความหวานเทียมคุณไม่จำเป็นต้องเติมน้ำตาล การใช้พารามิเตอร์ที่มีชื่อและแม้จะมีการใช้งานมากเกินไปก็เป็นการสร้างวิธีหนึ่งที่ทำได้ยากมาก และแน่นอนว่า Java ไม่ได้ตั้งชื่อพารามิเตอร์ดังนั้นอีกเหตุผลหนึ่งที่ผู้คนกำลังใช้รูปแบบตัวสร้าง
YoYo

0

พิจารณาSizeคลาสที่สรุปความกว้างและความสูง ฉันสามารถกำจัดตัวเซ็ตเตอร์โดยใช้ Constructor ได้ แต่นั่นช่วยฉันวาดสี่เหลี่ยมได้Sizeอย่างไร ความกว้างและความสูงไม่ใช่ข้อมูลภายในของคลาส พวกเขากำลังแบ่งปันข้อมูลที่จะต้องมีให้กับผู้บริโภคในขนาด

วัตถุประกอบด้วยพฤติกรรมและสถานะ - หรือคุณลักษณะ หากไม่มีสถานะเปิดเผยพฤติกรรมเท่านั้นที่เป็นสาธารณะ

หากไม่มีรัฐคุณจะจัดเรียงกลุ่มของวัตถุอย่างไร คุณจะค้นหาตัวอย่างของวัตถุได้อย่างไร หากคุณใช้คอนสตรัคเตอร์จะเกิดอะไรขึ้นเมื่อออบเจ็กต์ของคุณมีรายการคุณลักษณะยาว ๆ

ไม่ควรใช้พารามิเตอร์เมธอดโดยไม่มีการตรวจสอบความถูกต้อง ดังนั้นจึงเป็นความเกียจคร้านที่จะเขียน:

setMyField(int myField){
    this.myField = myField;
}

หากคุณเขียนด้วยวิธีดังกล่าวคุณจะต้องเตรียมใช้งานตัวตรวจสอบความถูกต้องอย่างน้อย มันดีกว่าสนามสาธารณะ - แต่แทบจะไม่ แต่อย่างน้อยคุณก็มีส่วนติดต่อสาธารณะที่สอดคล้องกันซึ่งคุณสามารถกลับมาและวางกฎการตรวจสอบโดยไม่ทำลายรหัสลูกค้าของคุณ

Getters, setters, คุณสมบัติ, mutators เรียกสิ่งที่คุณต้องการ แต่มันจำเป็น


แต่อย่างน้อยคุณก็มีส่วนติดต่อสาธารณะที่สอดคล้องกันซึ่งคุณสามารถกลับมาและวางกฎการตรวจสอบโดยไม่ทำลายรหัสลูกค้าของคุณ ที่ไม่เป็นความจริง. การเพิ่มกฎการตรวจสอบความถูกต้องไปตามถนนอาจเป็นไปได้อย่างมากที่จะ "ทำลายรหัสลูกค้าของคุณ" ใช้intตัวแปรเช่นตัวอย่างเช่นและจินตนาการว่าคุณตัดสินใจที่จะเพิ่มกฎการตรวจสอบที่จะยอมรับเฉพาะค่าไม่ติดลบ ปัญหาคือว่ารหัสลูกค้าของคุณอาจขึ้นอยู่กับความเป็นไปได้ในการตั้งค่าเป็นค่าลบ ...
jub0bs

0

หาก getters และ setters ละเมิด encapsulation และ OO จริงแสดงว่าฉันกำลังมีปัญหา

ฉันมักจะรู้สึกว่าวัตถุแสดงถึงสิ่งที่ดีที่สุดในใจที่คุณต้องการให้ทำ

ฉันเพิ่งเสร็จสิ้นการเขียนโปรแกรมที่สร้าง Mazes ใน Java และฉันมีคลาสที่แสดงถึง "Maze Squares" ฉันมีข้อมูลในคลาสนี้ที่แสดงถึงพิกัดผนังและบูลีน ฯลฯ

ฉันต้องมีวิธีที่จะเปลี่ยน / จัดการ / เข้าถึงข้อมูลนี้! ฉันจะทำอย่างไรหากไม่มีตัวตั้งและตัวตั้ง Java ไม่ได้ใช้คุณสมบัติและการตั้งค่าข้อมูลทั้งหมดของฉันที่เป็นแบบโลคัลสำหรับคลาสนี้เป็นแบบสาธารณะแน่นอนว่าเป็นการละเมิด encapsulation และ OO


6
นี่คือคำถาม: ถ้าคุณทำให้ฟิลด์เหล่านั้นเป็นสาธารณะและหยุดใช้ getters และ setters รหัสของคุณจะแตกต่างกันอย่างไร
Winston Ewert

ในทางทฤษฎีมันไม่ได้ ทำไมถึงเรียนในเวลานั้น อาร์กิวเมนต์เดียวกันสามารถทำอะไรก็ได้ แต่โพสต์ด้านล่างของฉันดูเหมือนจะพูดได้ดีกว่า (Getters และ setters เป็นวิธีที่จะได้อย่างปลอดภัยมอบมูลค่าให้กับวัตถุหรือเรียกค่าจากวัตถุที่.) โพสต์ไปที่ ..
ไบรอันแฮร์ริง

3
ฉันจะชี้ให้เห็น: ในที่สุดโปสเตอร์นั้นก็เห็นด้วยกับฉันและโพสต์คำตอบอีกครั้งสำหรับเอฟเฟกต์นั้น โดยพื้นฐานแล้วการใช้ getters และ setters นั้นเหมือนกับการจัดการข้อมูลโดยตรง คุณไม่ได้รับ OOness จริง ๆ โดยการทำเช่นนั้น เพื่อที่จะเป็น OO คุณควรให้ส่วนต่อประสานข้อมูลในระดับที่สูงขึ้น
Winston Ewert

4
ฉันคิดว่าวิธีที่ดีที่สุดในการอธิบายก็คือว่าคุณควรออกแบบส่วนต่อประสานของคุณจากด้านนอกไม่ใช่ด้านใน อินเทอร์เฟซที่วัตถุของคุณมีควรกำหนดโดยวิธีการใช้วัตถุไม่ใช่วิธีการนำไปใช้ ดังนั้นอย่าเขียนตัวรับและอนุญาตให้วัตถุภายนอกตีความข้อมูล ค้นหาคำถามที่พวกเขาต้องการคำตอบและเขียนวิธีการที่ตอบคำถามนั้น ไม่อนุญาตให้วัตถุภายนอกแก้ไขสถานะโดย setter ค้นหาการจัดการที่พวกเขาต้องการเพื่อดำเนินการและเขียนวิธีการทำ
Winston Ewert

2
ในบางกรณี Getters และ Setters เป็นวิธีที่ดีที่สุด บางครั้งพวกเขาเป็นอินเทอร์เฟซที่ดีที่สุดที่คุณสามารถให้ได้ อย่างไรก็ตามในหลายกรณีพวกเขาไม่ได้ ในหลายกรณีคุณเพิ่งรั่วรายละเอียดการใช้ไปยังคลาสอื่น
Winston Ewert

-1

ประการแรกมีวัตถุสองประเภทในวงกว้างที่ฉันจะแสดงความคิดเห็นเกี่ยวกับคุณค่าและประเภทของบริการ

ประเภทบริการไม่ควรมีตัวตั้งค่าใด ๆ ก็ตามที่การพึ่งพาที่พวกเขาต้องการไม่ควรเป็น gettable วิธีที่ดีที่สุดในการส่งผ่านการพึ่งพาคือผ่านตัวสร้างหรือโรงงานซึ่งวิธีการอินสแตนซ์ทั้งหมดจะเกิดขึ้นอย่างสมบูรณ์ตั้งแต่เริ่มต้นธรรมดาและเรียบง่าย

ประเภทของมูลค่าควรไม่เปลี่ยนรูปในทางตรงกันข้ามมีบางครั้งที่สิ่งนี้ไม่สามารถใช้งานได้เช่น ORM หรือการทำแผนที่อื่น ๆ เช่นจากวิดเจ็ตไปยังวัตถุ ประเภทค่าอื่น ๆ ทั้งหมดที่ผ่านรอบระบบจากชั้นหนึ่งหรือส่วนหนึ่งไปอีกประเภทหนึ่งควรเปลี่ยนรูปไม่ได้และไม่ควรมีตัวตั้งค่า


ฉันขอแนะนำประเภทที่สาม: คอนเทนเนอร์ที่ไม่แน่นอนซึ่งมีวัตถุประสงค์เพื่อเก็บค่าหนึ่งค่าขึ้นไป ในหลาย ๆ กรณีไม่ควรคาดหวังให้มีคอนเทนเนอร์ในลักษณะของตรรกะหรือการตรวจสอบความถูกต้อง รหัสที่ต้องการวิธีการคำนวณจำนวนเต็มบวกหกจำนวนอาจส่งผ่านคอนเทนเนอร์สำหรับจำนวนเต็มหกจำนวนไปยังวิธีที่จะเก็บผลลัพธ์ในนั้น ความรับผิดชอบในการตรวจสอบให้แน่ใจว่าตัวเลขเป็นค่าบวกโดยทั่วไปควรอยู่กับผู้เรียกหรือวิธีการที่เรียกว่าไม่ใช่กับภาชนะ
supercat

-1

Getter / Setter เป็นธรรมเช่นเดียวกับวิธีสาธารณะอื่น ๆ ที่เป็นธรรม เหตุผลส่วนใหญ่เป็นเพราะเราต้องการให้อินเทอร์เฟซกับโลกภายนอกที่กำหนดวิธีการที่คลาสของเราโต้ตอบกับคลาสอื่น เราทำสิ่งนี้เป็นส่วนใหญ่เพราะเราต้องการลดการแต่งงานระหว่างหน่วยงานที่แยกจากกัน ลดการมีเพศสัมพันธ์เป็นสิ่งที่ดีด้วยเหตุผลหลายประการ:

  • ฉันสามารถใช้จากรหัสปัจจุบันของฉันเป็นอินเทอร์เฟซคลาสเดียวกันได้แม้ว่าในขณะเดียวกันคลาสนั้นก็เพิ่มวิธีการใหม่ (แต่ยังคงอินเทอร์เฟซเก่าไว้)
  • สามารถเปลี่ยนการเป็นตัวแทนภายในของคลาสได้โดยไม่กระทบต่อผู้บริโภค
  • ลดโอกาสในการเกิดข้อผิดพลาด: ถ้าคุณทำให้ข้อมูลภายในของคุณเป็นส่วนตัวคุณสามารถรู้ได้ว่ารหัสภายนอกจะไม่ยุ่งกับข้อมูลภายในของคุณ

-1

ใช่ getters และ setters เป็นต่อต้านรูปแบบในการเขียนโปรแกรมเชิงวัตถุและควรไม่เคยถูกนำมาใช้: http://www.yegor256.com/2014/09/16/getters-and-setters-are-evil.html โดยสรุปแล้วพวกเขาไม่เหมาะกับกระบวนทัศน์เชิงวัตถุเพราะพวกเขาสนับสนุนให้คุณปฏิบัติต่อวัตถุเช่นโครงสร้างข้อมูล ซึ่งเป็นความเข้าใจผิดที่สำคัญ


2
นี้ไม่ได้ดูเหมือนจะนำเสนออะไรที่สำคัญกว่าจุดทำและอธิบายในก่อน 18 คำตอบ
ริ้น

4
มันยังเป็นบิตที่แข็งแกร่งที่จะบอกว่าไม่เคย
Winston Ewert

-4

ฉันหวังว่าทุกสิ่งที่ IDE พัฒนาขึ้นโดย บริษัท ที่พัฒนาโปรแกรมสร้างภาษาอัตโนมัติของคุณจะไม่ละเมิด "หลักการของการวางแนววัตถุ"

ที่ถูกกล่าวว่าเมื่อใดก็ตามที่คุณมีตัวแปรที่กำหนดขอบเขตสาธารณะใช้ตัวทะลุและตัวเซ็ตและคุณก็จะเป็นสีทอง ดูเหมือนว่าฉันจะเป็นองค์ประกอบที่จำเป็นของหลักการห่อหุ้มวัตถุอย่างยิ่งแม้ว่ามันจะดูเหมือนรหัสขยะจำนวนมากก็ตาม

เหตุผลที่จะใช้มันก็คือการห่อหุ้มที่เหมาะสมอาจเกิดขึ้นและตราบใดที่คุณแยกชั้นที่ให้บุคคลที่ลิงกับวัตถุของคุณรู้สึกถึงวัตถุของคุณคุณสามารถนำวัตถุนั้นไปได้โดยที่เขาไม่รู้

พอจะพูดได้ว่าบ้านแบ่งออกเป็นไม่สามารถยืนหนึ่งในผู้เช่า OO จะไม่เปิดตัวเองและคุณไม่สามารถให้บริการทั้งการห่อหุ้มและการเพิ่มประสิทธิภาพก่อนวัยอันควร


4
และสิ่งที่ฉันได้รับโดยการเพิ่มรหัสจำนวนมากเพื่อเรียก setFoo () และ getFoo () ทุกครั้งที่ฉันจัดการกับตัวแปร?
Winston Ewert

7
นี่คือสิ่งที่ฉันไม่คิดว่าคุณจะได้รับการห่อหุ้ม คุณยังคงจัดการสถานะของวัตถุจากที่อื่น คุณแค่ทำมันให้ละเอียดมากขึ้น ในการรับ encapsulation คุณจะต้องรวมศูนย์การจัดการค่าในคลาสที่เป็นเจ้าของค่านั้น สิ่งอื่นใดเป็นเพียงรหัสขั้นตอนในเสื้อผ้า OO (ไม่มีอะไรผิดปกติกับสิ่งนั้น แต่มันคือสิ่งที่มันเป็น)
Winston Ewert

2
ข้อดีของการห่อหุ้มก็คือตรรกะทั้งหมดที่เกี่ยวข้องกับค่าเฉพาะนั้นอยู่ในที่เดียว (มากหรือน้อย) ฉันไม่เข้าใจสิ่งนั้นด้วยตัวตั้งและตัวตั้ง ดังนั้นฉันไม่คิดว่าฉันจะได้รับประโยชน์มากมายสำหรับพวกเขา
Winston Ewert

1
อย่างไรก็ตามฉันจะยอมรับว่าฉันต้องการมีโค้ดพร้อมตัวเชื่อมต่อและตัวตั้งค่าจากนั้นรหัสที่จัดการข้อมูลอย่างอิสระผ่านการเข้าถึงสาธารณะ อย่างน้อยฉันก็สามารถแนบการตรวจสอบความถูกต้องของข้อมูลที่เข้ามา
Winston Ewert

3
แน่นอนว่าฉันไม่ใช่แฟนของการใช้คำฟุ่มเฟือย แต่การคัดค้านของฉันคือคนที่ทำให้ตัวแปรของพวกเขาเป็นส่วนตัวและจากนั้นเรียกผู้ได้รับและผู้ตั้งค่าให้พวกเขาจบลงอย่างอิสระโดยไม่มีความแตกต่าง ถ้าคุณต้องการใช้ getters / setters ภายในชั้นเรียนของคุณ คำถามคือทำไม ประโยชน์หลักที่ฉันทราบมีคือคุณสามารถทำการตรวจสอบข้อมูลเพื่อตรวจสอบข้อผิดพลาดก่อนหน้านี้ สิ่งนี้มีประโยชน์น้อยกว่าเมื่อรหัสทั้งหมดที่จัดการข้อมูลอยู่ในที่เดียวกัน แต่มันก็ยังคงมีประโยชน์ เป็นการดีที่คุณมีภาษาที่รองรับคุณสมบัติและสามารถหลีกเลี่ยงการใช้คำฟุ่มเฟื่อย
Winston Ewert

-4

ฉันคิดว่าเราจะมีคำตอบมากกว่าปกติที่นี่?

โดยทั่วไปแล้ว Getters และ setters จะมี OOP เป็นอย่างมาก

แม้ว่าคุณจะต้องจำไว้ว่าอย่าให้มากกว่าวิศวกร แต่อย่าสร้างทะเยอทะยานหรือหมาเซทเตอร์ที่ไม่จำเป็น ข้อมูลใด ๆ ที่คุณจะไม่ใช้โดยชั้นเรียนอื่นคุณไม่ควรมีผู้ทะเยอทะยานหรือผู้ตั้งค่า

แม้ว่าเหตุผลที่คุณไม่ได้ทำให้ฟิลด์เป็นสาธารณะและมีเกตเตอร์และเซทเทอร์แทน:

  • ไม่สามารถทำการทดสอบที่เหมาะสมโดยใช้ฟิลด์ Getters / setters นั้นดีกว่ามากในเรื่องนั้น

  • เป็นไปไม่ได้ที่จะใช้ฟิลด์อย่างถูกต้องในการตั้งค่าการเขียนโปรแกรมแบบเรียลไทม์ getters / setters ตรงกันเป็นวิธีที่จะไป

  • หัวข้ออินเทอร์เฟซ (อธิบายแล้วดังนั้นฉันจะไม่)

  • ง่ายต่อการใช้งานเมื่อนำระบบกลับมาใช้ใหม่อย่างเหมาะสม

  • เป็นเรื่องยากที่จะทราบว่าคลาสใดที่ใช้คลาสของคุณและสิ่งใดที่จะแตกถ้าคุณเปลี่ยนฟิลด์มากกว่า getter / setter

ดังนั้นในครั้งเดียวที่คุณใช้สนามสาธารณะแทนที่จะเป็นผู้ทะเยอทะยาน / ผู้ตั้งค่าคือเมื่อคุณไม่ได้ทำโครงการอย่างเป็นทางการ แต่เพียงทำเพื่อความสนุกและไม่ต้องกังวลกับผู้ทะเยอทะยาน / ผู้ตั้งค่า


2
+1 สำหรับการทดสอบ ตกใจที่ไม่มีใครพูดถึงมันก่อนหน้านี้ คุณสมบัติที่มีประโยชน์อีกประการของคุณสมบัติคือการแก้ไขข้อบกพร่อง (ง่ายต่อการแทรกเบรกพอยต์ในรหัสมากกว่าต้องการจุดหยุดฮาร์ดแวร์ / หน่วยความจำสำหรับฟิลด์)
Mark H

9
การคัดค้านต่อผู้ได้รับและผู้ตั้งตนก็คือพวกเขามักจะใช้ในการปฏิบัติตามตัวอักษรของกฎหมาย OOP ในขณะที่ไม่สนใจวิญญาณและความตั้งใจ OOP บอกว่าคุณไม่ควรอนุญาตให้วัตถุอื่นสร้างความขุ่นเคืองกับภายในของคุณ หากคุณกำหนดผู้ได้รับและผู้ตั้งค่าที่อนุญาตให้คุณทำเช่นนั้นได้คุณจะต้องฝ่าฝืน OOP
Winston Ewert

6
ฉันจะยอมรับว่ามีประโยชน์มากมายของผู้ได้รับและผู้ตั้งค่ามากกว่าเขตข้อมูลสาธารณะที่เรียบง่าย อย่างไรก็ตามฉันไม่ชัดเจนว่าการทดสอบนั้นดีกว่าอย่างไร คุณช่วยอธิบายได้ไหม
Winston Ewert

4
@Skarion: ฉันไม่เห็นด้วยกับคำตอบของคุณ ดูเหมือนว่าคุณกำลังนำเสนอสองทางเลือก: อาจใช้ getters / setters หรือทำให้ฟิลด์เป็นแบบสาธารณะ แต่มีตัวเลือกที่สามคือใช้ทั้ง getters / setters และไม่มีฟิลด์! ทำไมคุณต้องทดสอบสถานะของเขตข้อมูลภายใน คุณไม่ควรทดสอบ API สาธารณะของวัตถุของคุณหรือ
Andres F.
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.