คำอธิบายเกี่ยวกับวิธี“ บอกอย่าถาม” ถือว่าเป็น OO ที่ดี


49

บล็อกโพสต์นี้ถูกโพสต์ใน Hacker News พร้อมอัปโหลดหลายรายการ มาจาก C ++ ตัวอย่างเหล่านี้ส่วนใหญ่ดูเหมือนจะขัดแย้งกับสิ่งที่ฉันได้รับการสอน

เช่นตัวอย่าง # 2:

แย่:

def check_for_overheating(system_monitor)
  if system_monitor.temperature > 100
    system_monitor.sound_alarms
  end
end

เมื่อเทียบกับดี:

system_monitor.check_for_overheating

class SystemMonitor
  def check_for_overheating
    if temperature > 100
      sound_alarms
    end
  end
end

คำแนะนำใน C ++ คือคุณควรชอบฟังก์ชั่นฟรีแทนฟังก์ชั่นสมาชิกที่เพิ่มการห่อหุ้ม ทั้งสองอย่างนี้มีความหมายเหมือนกันดังนั้นเหตุใดจึงเลือกตัวเลือกที่มีการเข้าถึงสถานะเพิ่มเติม

ตัวอย่างที่ 4:

แย่:

def street_name(user)
  if user.address
    user.address.street_name
  else
    'No street name on file'
  end
end

เมื่อเทียบกับดี:

def street_name(user)
  user.address.street_name
end

class User
  def address
    @address || NullAddress.new
  end
end

class NullAddress
  def street_name
    'No street name on file'
  end
end

ทำไมจึงเป็นความรับผิดชอบของUserการจัดรูปแบบสตริงข้อผิดพลาดที่ไม่เกี่ยวข้อง? ถ้าฉันต้องการทำอะไรนอกเหนือจากการพิมพ์'No street name on file'ถ้าไม่มีถนน เกิดอะไรขึ้นถ้าถนนชื่อเดียวกัน


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


ตัวอย่างโค้ดอาจเป็น Ruby และไม่ใช่ Python ฉันไม่รู้
Pubby

2
ฉันมักจะสงสัยว่าบางอย่างเช่นตัวอย่างแรกนั้นไม่ใช่การละเมิด SRP หรือไม่?
stijn

1
คุณสามารถอ่านได้ที่: pragprog.com/articles/tell-dont-ask
Mik378

ทับทิม. ยกตัวอย่างเช่น @ is shorthand และ Python จบบล็อกโดยปริยายด้วยช่องว่าง
Erik Reppen

3
"คำแนะนำใน C ++ คือคุณควรจะชอบฟังก์ชั่นฟรีแทนฟังก์ชั่นสมาชิกเพราะมันจะเพิ่มการห่อหุ้ม" ฉันไม่รู้ว่าใครบอกคุณ แต่มันไม่จริง ฟังก์ชันฟรีสามารถใช้เพื่อเพิ่มการห่อหุ้มได้ แต่ไม่จำเป็นต้องเพิ่มการห่อหุ้ม
Rob K

คำตอบ:


81

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

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

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

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

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

http://pragprog.com/articles/tell-dont-ask


4
ข้อความตัวอย่างเช่นไม่อนุญาตให้หลายสิ่งที่เห็นได้ชัดว่าการปฏิบัติที่ดี
DeadMG

13
@DeadMG มันทำในสิ่งที่คุณพูดกับคนที่ทำตามอย่างทารุณผู้ที่เพิกเฉยต่อ "ปฏิบัติ" ในชื่อไซต์และความคิดหลักของผู้เขียนไซต์ที่ระบุไว้อย่างชัดเจนในหนังสือเล่มสำคัญ: "ไม่มีทางแก้ปัญหาที่ดีที่สุด ... "
gnat

2
ไม่เคยอ่านหนังสือ ฉันไม่ต้องการ ฉันอ่านข้อความตัวอย่างเท่านั้นซึ่งยุติธรรมอย่างสมบูรณ์
DeadMG

3
@DeadMG ไม่ต้องกังวล ตอนนี้คุณรู้แล้วว่าประเด็นสำคัญที่ทำให้ตัวอย่างนี้ (และอื่น ๆ จาก pragprog สำหรับเรื่องนั้น) ในบริบทที่ตั้งใจ ("ไม่มีสิ่งที่เป็นทางออกที่ดีที่สุด ... ") ก็โอเคที่จะไม่อ่านหนังสือ
gnat

1
ฉันยังไม่แน่ใจในสิ่งที่ Tell, Don't Ask ควรจะสะกดให้คุณโดยไม่มีบริบท แต่นี่เป็นคำแนะนำ OOP ที่ดีจริงๆ
Erik Reppen

16

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

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

ตัวอย่างเช่นถ้าระบบให้temperatureเป็นแบบสอบถามแล้วในวันพรุ่งนี้ลูกค้าสามารถโดยไม่ต้องเปลี่ยนcheck_for_underheating SystemMonitorนี่ไม่ใช่กรณีที่ตัวSystemMonitorดำเนินการcheck_for_overheatingเอง ดังนั้นSystemMonitorคลาสที่มีหน้าที่ยกสัญญาณเตือนเมื่ออุณหภูมิสูงเกินไปทำตามนี้ - แต่SystemMonitorคลาสที่มีหน้าที่อนุญาตให้โค้ดอีกชิ้นหนึ่งอ่านอุณหภูมิเพื่อให้สามารถควบคุมพูดได้ TurboBoost หรืออะไรทำนองนั้น , ไม่ควร.

โปรดทราบว่าตัวอย่างที่สองนั้นใช้ Null Object Anti-pattern อย่างไม่มีจุดหมาย


19
“ วัตถุว่างเปล่า” ไม่ใช่สิ่งที่ฉันเรียกว่ารูปแบบต่อต้านฉันจึงสงสัยว่าทำไมคุณถึงทำเช่นนั้น
Konrad Rudolph

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

4
ฉันขอยืนยันว่าทั้งหมดขึ้นอยู่กับโดเมนปัญหา
Konrad Rudolph

5
@DeadMG ผมยอมรับว่าตัวอย่างข้างต้นคือการใช้งานที่ไม่ดีของรูปแบบวัตถุ Null แต่มีเป็นบุญที่จะใช้มัน สองสามครั้งที่ฉันใช้ 'ไม่ใช้งาน' ของอินเทอร์เฟซบางอย่างหรืออื่น ๆ เพื่อหลีกเลี่ยงการตรวจสอบเป็นโมฆะหรือมี 'โมฆะจริง' ที่อนุญาตระบบ
Max

6
ไม่แน่ใจว่าฉันเห็นประเด็นของคุณด้วย "ลูกค้าทำได้check_for_underheatingโดยไม่ต้องเปลี่ยนSystemMonitor" ลูกค้าแตกต่างจากSystemMonitorณ จุดนั้นอย่างไร ตอนนี้คุณไม่กระจายตรรกะการตรวจสอบของคุณในหลาย ๆ คลาสหรือไม่ ฉันไม่เห็นปัญหาเกี่ยวกับคลาสมอนิเตอร์ที่ให้ข้อมูลเซ็นเซอร์แก่คลาสอื่น ๆ ในขณะที่สำรองฟังก์ชั่นสัญญาณเตือนด้วยตนเอง บูสเตอร์คอนโทรลเลอร์ควรควบคุมบูสต์โดยไม่ต้องกังวลเกี่ยวกับการเตือนหากอุณหภูมิสูงเกินไป
TMN

9

ปัญหาจริงของตัวอย่างความร้อนสูงเกินไปของคุณคือกฎสำหรับสิ่งที่มีคุณสมบัติเป็นความร้อนสูงเกินไปจะไม่แตกต่างกันสำหรับระบบที่แตกต่างกัน สมมติว่าระบบ A เป็นอย่างที่คุณมี (อุณหภูมิ> 100 ร้อนเกินไป) แต่ระบบ B มีความละเอียดอ่อนมากขึ้น (อุณหภูมิ> 93 ร้อนเกินไป) คุณเปลี่ยนฟังก์ชั่นการควบคุมของคุณเพื่อตรวจสอบประเภทของระบบแล้วใช้ค่าที่ถูกต้องหรือไม่?

if (system is a System_A and system_monitor.temp >100)
  system_monitor.sound_alarms
else if (system is a System_B and system_monitor.temp > 93)
  system_monitor.sound_alarms
end

หรือคุณมีระบบแต่ละประเภทกำหนดความสามารถในการทำความร้อน?

แก้ไข:

system.check_for_overheating

class SystemA : System
  def check_for_overheating
    if temperature > 100
      sound_alarms
    end
  end
end

class SystemB : System
  def check_for_overheating
    if temperature > 93
      sound_alarms
    end
  end
end

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


1
ทำไมไม่ให้แต่ละระบบลงทะเบียนกับจอภาพ ในระหว่างการลงทะเบียนพวกเขาสามารถระบุเมื่อเกิดความร้อนสูงเกินไป
Martin York

@ LokiAstari - คุณทำได้ แต่จากนั้นคุณสามารถเข้าสู่ระบบใหม่ที่ไวต่อความชื้นหรือความกดอากาศ หลักการคือการสรุปสิ่งที่แตกต่าง - ในกรณีนี้คือความไวต่อความร้อนสูงเกินไป
Matthew Flynn

1
นี่คือเหตุผลที่คุณควรมีแบบจำลองบอก คุณแจ้งให้ระบบทราบถึงสภาพปัจจุบันและแจ้งให้คุณทราบว่าอยู่นอกสภาพการทำงานปกติหรือไม่ วิธีที่คุณไม่จำเป็นต้องแก้ไข SystemMoniter นั่นคือการห่อหุ้มให้คุณ
Martin York

@ LokiAstari - ฉันคิดว่าเรากำลังพูดถึงจุดประสงค์ไขว้ที่นี่ - ฉันกำลังมองหาการสร้างระบบที่แตกต่างกันมากกว่าจอภาพที่แตกต่างกัน สิ่งที่เป็นคือระบบควรรู้ว่าเมื่อมันอยู่ในสถานะที่ทำให้เกิดการเตือนภัยซึ่งตรงข้ามกับฟังก์ชั่นควบคุมนอกบางส่วน SystemA ควรมีเกณฑ์ของมัน SystemB ควรมีของตัวเอง คอนโทรลเลอร์ควรจะสามารถถาม (ในช่วงเวลาปกติ) ว่าระบบนั้นใช้ได้หรือไม่
Matthew Flynn

6

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

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

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

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

ดังนั้นอาจมีกรณีที่ "ไม่ดี" เป็นวิธีที่จะไป แต่โดยทั่วไป "ดีกว่า" คือดีดีกว่า


3

ข้อมูล / วัตถุต่อต้านความสมมาตร

ดังที่คนอื่น ๆ ชี้ให้เห็นอย่าบอกเป็นพิเศษสำหรับกรณีที่คุณเปลี่ยนสถานะวัตถุหลังจากที่คุณถาม (ดูเช่นข้อความ Pragprog โพสต์ที่อื่นในหน้านี้) กรณีนี้ไม่ได้เกิดขึ้นเสมอไปเช่นวัตถุ 'ผู้ใช้' จะไม่เปลี่ยนแปลงหลังจากถูกขอให้ใส่ user.address ดังนั้นจึงเป็นที่ถกเถียงกันว่าเป็นกรณีที่เหมาะสมในการใช้ Tell-Dont-Ask

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

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

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

Bob Martin ในหนังสือของเขาที่ชื่อว่า "Clean Code" เรียกสิ่งนี้ว่า "Data / Object Anti-Symmetry" (หน้า 95ff) ชุมชนอื่น ๆ อาจเรียกมันว่า " ปัญหาการแสดงออก "


3

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

กฎนี้เกี่ยวข้องกับกฎเกี่ยวกับการหลีกเลี่ยงรหัส "double-dot" หรือ "double arrow" ซึ่งมักเรียกว่า 'Only คุยกับเพื่อนทันที' ซึ่งระบุว่าfoo->getBar()->doSomething()ไม่ดีแทนที่จะใช้foo->doSomething();ซึ่งเป็นการเรียก wrapper รอบฟังก์ชันการทำงานของแถบและ ดำเนินการตามที่เรียบง่ายreturn bar->doSomething();- หากfooมีหน้าที่ในการจัดการbarจากนั้นปล่อยให้ทำเช่นนั้น!


1

นอกจากคำตอบที่ดีอื่น ๆ เกี่ยวกับ "บอกไม่ต้องถาม" คำอธิบายบางอย่างเกี่ยวกับตัวอย่างเฉพาะของคุณที่อาจช่วยได้:

คำแนะนำใน C ++ คือคุณควรชอบฟังก์ชั่นฟรีแทนฟังก์ชั่นสมาชิกที่เพิ่มการห่อหุ้ม ทั้งสองอย่างนี้มีความหมายเหมือนกันดังนั้นเหตุใดจึงเลือกตัวเลือกที่มีการเข้าถึงสถานะเพิ่มเติม

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

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

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


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

แน่นอนหรือถ้าเทอร์โมและสัญญาณเตือนมีอยู่ในคลาสที่แตกต่างกัน (ตามที่ควรจะเป็น)
Telastyn

1
@DeadMG: คำแนะนำทั่วไปคือการทำให้สิ่งที่เป็นส่วนตัว / ป้องกันจนกว่าคุณจะต้องเข้าถึงพวกเขา ในขณะที่ตัวอย่างนี้คือ meh ที่ไม่ได้ขัดแย้งกับการปฏิบัติมาตรฐาน
Guvante

ตัวอย่างในบทความเกี่ยวกับการฝึกเป็น 'meh' kinda ข้อพิพาทมัน หากการปฏิบัตินี้เป็นมาตรฐานเพราะมันเป็นประโยชน์อย่างมากแล้วทำไมปัญหาในการหาตัวอย่างที่เหมาะสม?
Stijn de Witt

1

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

Product product = productMgr.get(productUuid)
if (product.userUuid != currentUser.uuid) {
    throw BlahException("This product doesn't belong to this user")
}

นั่นหมายความว่าคุณควรมีสิ่งนี้:

Product product = productMgr.get(productUuid, currentUser)

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


0

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

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

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

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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.