ฟิลด์บูลีนใหม่ดีกว่าการอ้างอิงค่า Null หรือไม่หากค่าสามารถขาดหายไปอย่างมีความหมายได้


39

ตัวอย่างเช่นสมมติว่าฉันมีคลาสMemberซึ่งมี lastChangePasswordTime:

class Member{
  .
  .
  .
  constructor(){
    this.lastChangePasswordTime=null,
  }
}

ซึ่ง lastChangePasswordTime อาจไม่มีความหมายเนื่องจากสมาชิกบางคนอาจไม่เปลี่ยนรหัสผ่าน

แต่ถ้าหาก nulls เป็นสิ่งชั่วร้ายสิ่งที่ควรใช้เมื่อค่าสามารถขาดความหมายได้อย่างไร และhttps://softwareengineering.stackexchange.com/a/12836/248528ฉันไม่ควรใช้ null เพื่อแสดงค่าขาดหายไปอย่างมีความหมาย ดังนั้นฉันพยายามเพิ่มธงบูลีน:

class Member{
  .
  .
  .
  constructor(){
    this.isPasswordChanged=false,
    this.lastChangePasswordTime=null,
  }
}

แต่ฉันคิดว่ามันค่อนข้างล้าสมัยเพราะ:

  1. เมื่อ isPasswordChanged เป็นเท็จ lastChangePasswordTime จะต้องเป็นโมฆะและการตรวจสอบ lastChangePasswordTime == null เกือบจะเหมือนกันกับการตรวจสอบ isPasswordChanged เป็นเท็จดังนั้นฉันชอบเช็ค lastChangePasswordTime == null โดยตรง

  2. เมื่อเปลี่ยนลอจิกที่นี่ฉันอาจลืมอัปเดตทั้งสองฟิลด์

หมายเหตุ: เมื่อผู้ใช้เปลี่ยนรหัสผ่านฉันจะบันทึกเวลาเช่นนี้:

this.lastChangePasswordTime=Date.now();

ฟิลด์บูลีนเพิ่มเติมดีกว่าการอ้างอิงโมฆะที่นี่หรือไม่


51
คำถามนี้ค่อนข้างเฉพาะภาษาเพราะสิ่งที่ถือเป็นทางออกที่ดีขึ้นอยู่กับสิ่งที่ภาษาโปรแกรมของคุณให้ ยกตัวอย่างเช่นใน C ++ 17 หรือ Scala คุณต้องการใช้หรือstd::optional Optionในภาษาอื่นคุณอาจต้องสร้างกลไกที่เหมาะสมด้วยตัวคุณเองหรือคุณอาจหันไปใช้nullหรือสิ่งที่คล้ายกันเพราะมันเป็นสำนวนมากกว่า
Christian Hackl

16
มีเหตุผลที่คุณไม่ต้องการให้ LastChangePasswordTime ตั้งค่าเวลาสร้างรหัสผ่านหรือไม่ (การสร้างเป็น mod หลังจากทั้งหมด) ใช่หรือไม่
Kristian H

@ChristianHackl อืมเห็นด้วยว่ามีวิธีการแก้ปัญหา "สมบูรณ์แบบ" ที่แตกต่างกัน แต่ฉันไม่เห็นภาษาใด ๆ (หลัก) แม้ว่าการใช้บูลีนแบบแยกจะเป็นความคิดที่ดีกว่าโดยทั่วไปในการตรวจสอบ null / nil ไม่แน่ใจทั้งหมดเกี่ยวกับ C / C ++ เนื่องจากฉันไม่ได้ใช้งานที่นั่นมาระยะหนึ่งแล้ว
Frank Hopkins

@FrankHopkins: ตัวอย่างจะเป็นภาษาที่ตัวแปรไม่สามารถกำหนดค่าเริ่มต้นเช่น C หรือ C ++ lastChangePasswordTimeอาจเป็นตัวชี้ที่ไม่ได้กำหนดค่าเริ่มต้นและการเปรียบเทียบกับสิ่งใด ๆ จะเป็นพฤติกรรมที่ไม่ได้กำหนด ไม่ใช่เหตุผลที่น่าสนใจจริงๆที่จะไม่เริ่มต้นตัวชี้ไปที่NULL/ nullptrแทนโดยเฉพาะใน C ++ ที่ทันสมัย ​​(ซึ่งคุณจะไม่ใช้ตัวชี้เลย) แต่ใครจะรู้ล่ะ อีกตัวอย่างหนึ่งคือภาษาที่ไม่มีตัวชี้หรือด้วยการสนับสนุนตัวชี้ที่ไม่ดี (FORTRAN 77 อยู่ในใจ ... )
Christian Hackl

ฉันจะใช้ Enum กับ 3 กรณีสำหรับเรื่องนี้ :)
J. Doe

คำตอบ:


72

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

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

class Member {
    DateTime lastChangePasswordTime = null;
    bool isPasswordChanged() { return lastChangePasswordTime != null; }

}

ในความคิดของฉันทำแบบนี้:

  • ให้โค้ดที่อ่านง่ายกว่าการตรวจสอบค่า null ซึ่งอาจทำให้บริบทเสียไป
  • ขจัดความต้องการที่คุณจะต้องกังวลเกี่ยวกับการรักษาisPasswordChangedคุณค่าที่คุณพูดถึง

วิธีที่คุณยืนยันข้อมูล (สมมุติในฐานข้อมูล) จะรับผิดชอบในการตรวจสอบให้แน่ใจว่าเก็บรักษาโมฆะไว้


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

28
ฉันจะทำให้มันแข็งแกร่งขึ้นเล็กน้อยเพราะไม่มีตัวแปรสองตัวที่รักษาสถานะเดิมเอาไว้ มันจะล้มเหลว การซ่อนค่าว่างไว้สมมติว่าค่าว่างนั้นสมเหตุสมผลภายในตัวอย่างจากด้านนอกเป็นสิ่งที่ดีมาก ในกรณีนี้คุณอาจตัดสินใจในภายหลังว่า 1970-01-01 แสดงว่ารหัสผ่านไม่เคยมีการเปลี่ยนแปลง จากนั้นตรรกะของส่วนที่เหลือของโปรแกรมไม่จำเป็นต้องใส่ใจ
Bent

3
คุณสามารถลืมโทรได้isPasswordChangedเหมือนที่คุณสามารถลืมตรวจสอบว่าเป็นโมฆะหรือไม่ ฉันไม่เห็นอะไรมาที่นี่
Gherman

9
@Gherman หากผู้บริโภคไม่เข้าใจว่า null มีความหมายหรือต้องการตรวจสอบคุณค่าที่มีอยู่เขาจะหลงทาง แต่ถ้าใช้วิธีนั้นมันชัดเจนสำหรับทุกคนที่อ่านรหัสว่าทำไมถึงมี เป็นการตรวจสอบและมีโอกาสที่สมเหตุสมผลที่ค่าเป็นโมฆะ / ไม่มีอยู่ มิฉะนั้นจะไม่ชัดเจนหากเป็นเพียงนักพัฒนาที่เพิ่มการตรวจสอบค่า Null เพียง "เพราะเหตุใด" หรือเป็นส่วนหนึ่งของแนวคิด แน่นอนว่าคนหนึ่งสามารถค้นพบ แต่วิธีหนึ่งที่คุณมีข้อมูลโดยตรงอื่น ๆ ที่คุณต้องพิจารณาในการใช้งาน
Frank Hopkins

2
@ FrankHopkins: จุดดี แต่ถ้าใช้พร้อมกันแม้การตรวจสอบตัวแปรเดียวอาจต้องล็อค
Christian Hackl

63

nullsไม่ใช่ความชั่วร้าย ใช้พวกเขาโดยไม่ต้องคิดคือ นี่เป็นกรณีที่nullตรงกับคำตอบที่ถูกต้อง - ไม่มีวันที่

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

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


17
ในอดีตnullมีอยู่เพราะ Tony Hoare ทำผิดพลาดพันล้านดอลลาร์ในปี 1965 คนที่อ้างว่าnull"ชั่วร้าย" กำลังทำให้หัวข้อง่ายขึ้น แต่เป็นเรื่องดีที่ภาษาสมัยใหม่หรือรูปแบบการเขียนโปรแกรมกำลังnullเปลี่ยนไปแทนที่ มันมีประเภทตัวเลือกเฉพาะ
Christian Hackl

9
@ChristianHackl: เพิ่งออกมาจากความสนใจทางประวัติศาสตร์ - ตาย Hoare เคยพูดในสิ่งที่ทางเลือกการปฏิบัติที่ดีกว่าจะได้รับ (โดยไม่ต้องเปลี่ยนกระบวนทัศน์ใหม่อย่างสมบูรณ์)?
AnoE

5
@AnoE: คำถามที่น่าสนใจ ไม่รู้ว่า Hoare พูดอะไรกันบ้าง แต่การเขียนโปรแกรมแบบไม่มีค่าใช้จ่ายมักเป็นความจริงในทุกวันนี้ในภาษาการเขียนโปรแกรมที่ทันสมัยและออกแบบมาอย่างดี
Christian Hackl

10
@ วัดอะไร ในภาษาเช่น C # และ Java DateTimeฟิลด์จะเป็นตัวชี้ แนวคิดทั้งหมดของnullเพียงทำให้รู้สึกสำหรับตัวชี้!
ทอดด์ซีเวลล์

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

29

ขึ้นอยู่กับภาษาการเขียนโปรแกรมของคุณอาจมีทางเลือกที่ดีเช่นoptionalชนิดข้อมูล ใน C ++ (17) นี้จะเป็นมาตรฐาน :: ตัวเลือก มันอาจจะขาดหรือมีค่าโดยพลการของชนิดข้อมูลพื้นฐาน


8
นอกจากนี้Optionalใน java เกินไป ความหมายของโมฆะOptionalขึ้นอยู่กับคุณ ...
Matthieu M.

1
มาที่นี่เพื่อเชื่อมต่อกับตัวเลือกเช่นกัน ฉันเข้ารหัสสิ่งนี้เป็นภาษาที่มีพวกเขา
Zipp

2
@ FrankHopkins เป็นเรื่องน่าอายที่ไม่มีอะไรใน Java ป้องกันคุณจากการเขียนOptional<Date> lastPasswordChangeTime = null;แต่ฉันจะไม่ยอมแพ้เพราะสิ่งนั้น แต่ฉันจะปลูกฝังกฎทีมที่จัดขึ้นอย่างแน่นหนาว่าจะไม่อนุญาตให้มีค่าnullเพิ่มเติม ตัวเลือกซื้อคุณคุณสมบัติที่ดีมากเกินไปที่จะยอมแพ้อย่างง่ายดาย คุณสามารถกำหนดค่าเริ่มต้นได้อย่างง่ายดาย ( orElseหรือด้วยการประเมินที่ขี้เกียจ:) orElseGet, โยนข้อผิดพลาด ( orElseThrow), แปลงค่าในวิธีที่ปลอดภัยเป็นโมฆะ ( map, flatmap) ฯลฯ
Alexander

5
@ FrankHopkins Checking isPresentมักจะเป็นกลิ่นรหัสในประสบการณ์ของฉันและเป็นสัญญาณที่น่าเชื่อถือว่าผู้พัฒนาที่ใช้ออปชั่นเหล่านี้ "ขาดประเด็น" อันที่จริงแล้วมันไม่ได้ให้ประโยชน์โดยทั่วไปref == nullแต่ก็ไม่ใช่สิ่งที่คุณควรใช้บ่อย ๆ แม้ว่าทีมจะไม่เสถียรเครื่องมือการวิเคราะห์แบบสแตติกสามารถวางกฎหมายเช่น linter หรือFindBugsซึ่งสามารถจับกรณีส่วนใหญ่
Alexander

5
@ FrankHopkins: อาจเป็นไปได้ว่าชุมชน Java ต้องการการเปลี่ยนกระบวนทัศน์เล็กน้อยซึ่งอาจใช้เวลาหลายปี ตัวอย่างเช่นถ้าคุณดูที่ Scala มันรองรับnullเพราะภาษานั้นรองรับภาษา Java ได้ 100% แต่ไม่มีใครใช้มันและOption[T]อยู่ทั่วทุกแห่งด้วยการสนับสนุนการเขียนโปรแกรมฟังก์ชั่นที่ยอดเยี่ยมเช่นmap, การflatMapจับคู่รูปแบบและอื่น ๆ ห่างไกลไกลเกินกว่า== nullการตรวจสอบ ในทางทฤษฎีแล้วคุณมีประเภทของตัวเลือกที่ดูเหมือนตัวชี้ที่น่ายกย่องน้อยกว่า แต่ความเป็นจริงพิสูจน์ว่าการโต้แย้งนั้นผิด
Christian Hackl

11

ใช้ null ให้ถูกต้อง

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

ในสถานการณ์เหล่านี้คุณส่วนใหญ่ใช้มันในลักษณะนี้ (ในรหัสหลอก):

if (value is null) {
  doSomethingAboutIt();
  return;
}

doSomethingUseful(value);

ปัญหา

และมันก็มีปัญหาใหญ่มาก ปัญหาคือตามเวลาที่คุณเรียกใช้doSomethingUsefulค่าอาจไม่ได้รับการตรวจสอบnull! หากไม่เป็นเช่นนั้นโปรแกรมจะเกิดข้อผิดพลาด และผู้ใช้อาจไม่เห็นข้อความแสดงข้อผิดพลาดใด ๆ ที่ถูกทิ้งไว้กับบางสิ่งเช่น "ข้อผิดพลาดที่น่ากลัว: ค่าที่ต้องการ แต่ได้รับค่าว่าง!" (หลังจากอัปเดต: แม้ว่าอาจมีข้อผิดพลาดที่ให้ข้อมูลน้อยลงเช่นSegmentation fault. Core dumped.หรือแย่กว่านั้นก็ไม่มีข้อผิดพลาดและการจัดการที่ไม่ถูกต้องในค่า null ในบางกรณี)

การลืมตรวจสอบการเขียนnullและการจัดการnullสถานการณ์เป็นปัญหาที่พบบ่อยมาก นี่คือเหตุผลที่ Tony Hoare ผู้คิดค้นnullกล่าวในการประชุมซอฟต์แวร์ชื่อ QCon London ในปี 2009 ว่าเขาทำผิดพลาดนับพันล้านดอลลาร์ในปี 1965: https://www.infoq.com/presentations/Null-References-The-Billion-Dollar- ผิดพลาดโทนี่โฮร์

หลีกเลี่ยงปัญหา

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

ตัวอย่างเช่น Haskell มีMaybemonad แทนที่จะเป็น nulls สมมติว่าDatabaseRecordเป็นประเภทที่ผู้ใช้กำหนด ใน Haskell ค่าชนิดMaybe DatabaseRecordสามารถจะเท่ากับหรือมันอาจจะเท่ากับJust <somevalue> Nothingจากนั้นคุณสามารถใช้งานได้หลายวิธี แต่ไม่ว่าคุณจะใช้งานอย่างไรคุณไม่สามารถใช้การดำเนินการบางอย่างNothingโดยที่ไม่รู้ตัว

เช่นฟังก์ชันนี้เรียกว่าzeroAsDefaultreturn xfor Just xและ0for Nothing:

zeroAsDefault :: Maybe Int -> Int
zeroAsDefault mx = case mx of
    Nothing -> 0
    Just x -> x

Christian Hackl กล่าวว่า C ++ 17 และ Scala มีวิธีการของตนเอง ดังนั้นคุณอาจต้องการลองดูว่าภาษาของคุณมีอะไรแบบนั้นและใช้มันไหม

Nulls ยังคงใช้งานได้อย่างกว้างขวาง

หากคุณไม่มีอะไรที่ดีกว่าการใช้nullก็ดี เพียงแค่คอยระวัง พิมพ์ประกาศในฟังก์ชั่นจะช่วยให้คุณค่อนข้างอยู่แล้ว

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

ตามข้อเสนอของคุณ

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

วิธีที่จะไม่ใช้ null

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

จากจุดยืนพีชคณิตสตริงว่างสำหรับสตริงนั้นมีค่าเท่ากับ 0 สำหรับตัวเลขนั่นคือเอกลักษณ์:

a+0=a
concat(str, '')=str

สตริงว่างเปล่าทำให้สตริงโดยทั่วไปกลายเป็น monoid: https://en.wikipedia.org/wiki/Monoid ถ้าคุณไม่เข้าใจมันไม่ใช่เรื่องสำคัญสำหรับคุณ

ตอนนี้เรามาดูกันว่าเหตุใดการเขียนโปรแกรมด้วยตัวอย่างนี้จึงมีความสำคัญ:

for (element in array) {
  doSomething(element);
}

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

วิธีจัดการ null

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


5
จริงๆแล้วhorrible error: wanted value but got null!มันดีกว่ารุ่นทั่วไปมากกว่าSegmentation fault. Core dumped....
Toby Speight

2
@TobySpeight ทรู Error: the product you want to buy is out of stockแต่ฉันต้องการบางสิ่งบางอย่างที่วางแง่ของผู้ใช้ภายในเช่น
Gherman

แน่นอน - ฉันเพิ่งสังเกตว่ามันอาจจะแย่กว่านั้น(และบ่อยครั้ง) ฉันเห็นด้วยอย่างสมบูรณ์ในสิ่งที่จะดีกว่า! และคำตอบของคุณเป็นสิ่งที่ฉันจะพูดกับคำถามนี้: +1
Toby Speight

2
@Gherman: ผ่านnullที่nullไม่ได้รับอนุญาตเป็นข้อผิดพลาดในการเขียนโปรแกรมเช่นข้อบกพร่องในรหัส สินค้าที่หมดสต็อกเป็นส่วนหนึ่งของตรรกะทางธุรกิจปกติไม่ใช่ข้อผิดพลาด คุณไม่สามารถและไม่ควรลองแปลการตรวจจับข้อบกพร่องเป็นข้อความปกติในส่วนติดต่อผู้ใช้ การหยุดทำงานในทันทีและไม่เรียกใช้รหัสมากขึ้นเป็นวิธีการปฏิบัติที่ต้องการโดยเฉพาะอย่างยิ่งหากเป็นแอปพลิเคชันที่สำคัญ
Christian Hackl

1
@EricDuminil เราต้องการลบ (หรือลด) ความเป็นไปได้ในการทำผิดพลาดโดยไม่ต้องลบnullตัวเองออกทั้งหมดแม้กระทั่งจากพื้นหลัง
Gherman

4

นอกเหนือจากคำตอบที่ดีทั้งหมดที่ได้รับก่อนหน้านี้แล้วฉันจะเพิ่มว่าทุกครั้งที่คุณอยากให้ฟิลด์เป็นโมฆะลองคิดให้ดีถ้าเป็นประเภทรายการ ประเภท nullable เท่ากับรายการขององค์ประกอบ 0 หรือ 1 และบ่อยครั้งที่สิ่งนี้สามารถทำให้เป็นรายการทั่วไปขององค์ประกอบ N โดยเฉพาะในกรณีนี้คุณอาจต้องการที่จะต้องพิจารณาเป็นรายชื่อของlastChangePasswordTimepasswordChangeTimes


นั่นเป็นจุดที่ยอดเยี่ยม เช่นเดียวกันมักจะเป็นจริงสำหรับประเภทตัวเลือก ตัวเลือกที่สามารถมองเห็นเป็นกรณีพิเศษของลำดับ
Christian Hackl

2

ถามตัวคุณเองว่าพฤติกรรมแบบใดที่ต้องใช้ฟิลด์เป็นครั้งสุดท้ายเปลี่ยนรหัสผ่านเวลา

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

class Member{
   private DateTime lastChangePasswordTime;

   public Member(DateTime lastChangePasswordTime) {
      // set value, maybe check for null
   }

   public bool IsPasswordExpired() {
      DateTime limit = DateTime.Now.AddMonths(-3);
      return lastChangePasswordTime < limit;
   }
}

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

class Member{
   private DateTime lastChangePasswordTime;
   private bool passwordShouldBeChanged;

   public Member(DateTime lastChangePasswordTime, bool passwordShouldBeChanged) {
      // set values, maybe check for nulls
   }

   public bool ShouldChangePassword() {
      return PasswordExpired(lastChangePasswordTime) || passwordShouldBeChanged;
   }

   private static bool PasswordExpired(DateTime lastChangePasswordTime) {
      DateTime limit = DateTime.Now.AddMonths(-3);
      return lastChangePasswordTime < limit;
   }
}

ทำให้ความตั้งใจของคุณชัดเจนในรหัส


2

ข้อแรกข้อเสียของความชั่วคือความเชื่อและตามปกติกับความเชื่อมันใช้งานได้ดีที่สุดในฐานะเป็นแนวทางและไม่ผ่านการทดสอบผ่าน / ไม่ผ่าน

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

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


1

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

ไม่มีคำตอบที่ถูกต้องเดียว ขึ้นอยู่กับสิ่งที่คุณกังวล

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

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

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