หากคุณส่งข้อมูลขั้นต่ำเปล่าไปยังฟังก์ชั่นในกรณีเช่นนี้เสมอ


81

สมมติว่าฉันมีฟังก์ชั่นIsAdminที่จะตรวจสอบว่าผู้ใช้เป็นผู้ดูแลระบบหรือไม่ สมมติว่าการตรวจสอบของผู้ดูแลระบบทำได้โดยการจับคู่ id ผู้ใช้ชื่อและรหัสผ่านกับกฎบางประเภท (ไม่สำคัญ)

ในหัวของฉันมีสองลายเซ็นฟังก์ชันที่เป็นไปได้สำหรับสิ่งนี้:

public bool IsAdmin(User user);
public bool IsAdmin(int id, string name, string password);

ฉันมักจะไปที่ลายเซ็นประเภทที่สองโดยคิดว่า:

  • ฟังก์ชั่นลายเซ็นช่วยให้ผู้อ่านมีข้อมูลมากขึ้น
  • ตรรกะที่มีอยู่ในฟังก์ชั่นไม่จำเป็นต้องรู้เกี่ยวกับUserชั้นเรียน
  • มันมักจะส่งผลให้รหัสน้อยลงเล็กน้อยภายในฟังก์ชั่น

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

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

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


40
หัวข้อ: นอกจากความอยากรู้อยากเห็นแล้วเหตุใดสถานะ "is admin" ของผู้ใช้จึงขึ้นอยู่กับรหัสผ่านของพวกเขา
stakx

43
@ syb0rg ผิด ใน C # นั่นคือการตั้งชื่อ
magnattic

68
@ syb0rg ใช่แล้วเขาไม่ได้ระบุภาษาดังนั้นฉันคิดว่ามันค่อนข้างแปลกที่จะบอกเขาว่าเขากำลังละเมิดข้อตกลงของภาษาหนึ่ง ๆ
magnattic

31
@ syb0rg ข้อความทั่วไปที่ว่า "ชื่อฟังก์ชั่นไม่ควรเริ่มต้นด้วยตัวอักษรตัวพิมพ์ใหญ่" ผิดเนื่องจากมีภาษาที่ควรใช้ อย่างไรก็ตามฉันไม่ได้ตั้งใจที่จะทำให้คุณขุ่นเคืองฉันแค่พยายามทำให้ชัดเจน นี่เป็นการปิดประเด็นให้กับตัวเอง ฉันไม่เห็นความจำเป็น แต่ถ้าคุณต้องการดำเนินการต่อให้ย้ายการอภิปรายกับการแชท
magnattic

6
เช่นเดียวกับจุดทั่วไปกลิ้งรักษาความปลอดภัยของคุณเองมักจะเป็นสิ่งที่ไม่ดี (TM) ภาษาและกรอบงานส่วนใหญ่มีระบบรักษาความปลอดภัย / สิทธิ์ใช้งานและมีเหตุผลที่ดีสำหรับการใช้งานแม้ว่าคุณจะต้องการสิ่งที่เรียบง่ายกว่าก็ตาม
James Snell

คำตอบ:


123

ฉันเองชอบวิธีแรกเพียง IsAdmin(User user)

มันใช้งานง่ายกว่ามากและหากเกณฑ์ IsAdmin ของคุณเปลี่ยนแปลงในภายหลัง (อาจขึ้นอยู่กับบทบาทหรือ isActive) คุณไม่จำเป็นต้องเขียนลายเซ็นวิธีของคุณใหม่ทุกที่

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

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


3
ฉันคิดว่าปัญหาการปรับโครงสร้างเป็นจุดที่ดีมาก - ขอบคุณ
Anders Arpi

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

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

รูปแบบการต่อต้านความหลงใหลดั้งเดิมอาจเป็นเรื่องที่น่ากลัวสำหรับการทดสอบหน่วย
ซามูเอล

82

ลายเซ็นแรกนั้นเหนือกว่าเพราะช่วยให้การห่อหุ้มของตรรกะที่เกี่ยวข้องกับผู้ใช้ในUserวัตถุนั้น มันไม่มีประโยชน์ที่จะมีตรรกะสำหรับการสร้าง "id, ชื่อ, รหัสผ่าน" tuple เกลื่อนกลาดเกี่ยวกับฐานรหัสของคุณ ยิ่งไปกว่านั้นมันทำให้isAdminฟังก์ชั่นซับซ้อน: เกิดอะไรขึ้นถ้ามีคนผ่านไปในidที่ไม่ตรงกับnameตัวอย่างเช่น? ถ้าคุณต้องการตรวจสอบว่าผู้ใช้ที่ได้รับเป็นผู้ดูแลระบบจากบริบทที่คุณไม่ควรรู้รหัสผ่านหรือไม่

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


45
การตามตรรกะของคุณจะไม่user.IsAdmin()ดีกว่านี้อีกหรือ
Anders Arpi

13
ใช่แล้ว
asthasr

6
@ AndersHolmströmขึ้นอยู่กับว่าคุณกำลังทดสอบว่าผู้ใช้เป็นผู้ดูแลระบบทั่วไปหรือเพียงแค่เป็นผู้ดูแลระบบสำหรับหน้า / แบบฟอร์มปัจจุบันที่คุณใช้อยู่ ถ้าโดยทั่วไปแล้วใช่ว่าจะดีกว่า แต่ถ้าคุณกำลังทดสอบIsAdminเฉพาะรูปแบบหรือฟังก์ชั่นเฉพาะที่ไม่ควรเกี่ยวข้องกับผู้ใช้
Rachel

40
@Anders: ไม่ควรทำ ผู้ใช้ไม่ควรตัดสินใจว่าเป็นผู้ดูแลหรือไม่ สิทธิพิเศษหรือระบบความปลอดภัยควร สิ่งที่เป็นคู่กับชั้นเรียนแน่นไม่ได้หมายความว่ามันเป็นความคิดที่ดีที่จะทำให้มันเป็นส่วนหนึ่งของชั้นเรียนนั้น
Marjan Venema

11
@MarjanVenema - ความคิดที่ว่าคลาสผู้ใช้จะต้องไม่ "ตัดสินใจ" ว่าอินสแตนซ์นั้นเป็นผู้ดูแลระบบหรือไม่นั้นทำให้ฉันรู้สึกเหมือนเป็นบิตของสินค้า คุณไม่สามารถทำให้ข้อสรุปทั่วไปเป็นอย่างนั้นได้ หากความต้องการของคุณซับซ้อนอาจเป็นประโยชน์ในการสรุปใน "ระบบ" แยกต่างหาก แต่อ้างถึง KISS + YAGNI ฉันต้องการตัดสินใจว่าต้องเผชิญกับความซับซ้อนนั้นจริง ๆ และไม่ใช่กฎทั่วไป :-) และโปรดทราบว่าแม้ว่าตรรกะไม่ใช่ "ส่วน" ของผู้ใช้มันยังคงมีประโยชน์ในแง่ของการใช้งานได้จริงเพื่อให้ผู้ใช้ส่งผ่านไปยังผู้ใช้ที่เพิ่งมอบหมายให้ระบบที่ซับซ้อนมากขึ้น
Eamon Nerbonne

65

ครั้งแรก แต่ไม่ (เท่านั้น) สำหรับเหตุผลที่คนอื่นได้ให้

public bool IsAdmin(User user);

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

public bool IsAdmin(int id, string name, string password);

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

สันนิษฐานว่าทั้งสองฟังก์ชั่นต้องการ user.getId (), user.getName () และ user.getPassword () ถูกเรียกทั้งในฟังก์ชั่น (ในกรณีแรก) หรือก่อนที่จะเรียกฟังก์ชั่น (ในครั้งที่สอง) ดังนั้น ปริมาณของคัปปลิ้งก็เหมือนกัน ที่จริงแล้วเนื่องจากฟังก์ชั่นนี้ใช้ได้เฉพาะกับผู้ใช้ใน Java ฉันจะกำจัดข้อโต้แย้งทั้งหมดและทำให้มันเป็นวิธีการเช่นในวัตถุผู้ใช้:

user.isAdmin();

เนื่องจากฟังก์ชั่นนี้เชื่อมโยงกับผู้ใช้อย่างแน่นหนาจึงเหมาะสมที่จะทำให้มันเป็นส่วนหนึ่งของผู้ใช้

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


11
ผู้ใช้ไม่ควรตัดสินใจว่าเป็นผู้ดูแลหรือไม่ สิทธิพิเศษหรือระบบความปลอดภัยควร สิ่งที่อยู่คู่กับคลาสอย่างแน่นหนาไม่ได้หมายความว่าเป็นความคิดที่ดีที่จะทำให้มันเป็นส่วนหนึ่งของคลาสนั้น
Marjan Venema

6
@MarjanVenema ผู้ใช้ไม่ได้ตัดสินใจอะไร วัตถุผู้ใช้ / ตารางเก็บข้อมูลเกี่ยวกับผู้ใช้แต่ละคน ผู้ใช้จริงไม่ได้เปลี่ยนทุกอย่างเกี่ยวกับตัวเอง แม้ว่าผู้ใช้จะเปลี่ยนสิ่งที่พวกเขาได้รับอนุญาตก็อาจเรียกการแจ้งเตือนความปลอดภัยเช่นอีเมลหากพวกเขาเปลี่ยนที่อยู่อีเมลหรือ ID ผู้ใช้หรือรหัสผ่าน คุณใช้ระบบที่ผู้ใช้สามารถเปลี่ยนทุกอย่างเกี่ยวกับวัตถุบางประเภทได้หรือไม่? ฉันไม่คุ้นเคยกับระบบดังกล่าว
GlenPeterson

2
@GlenPeterson: คุณตั้งใจเข้าใจฉันผิดหรือเปล่า? เมื่อฉันพูดผู้ใช้แน่นอนว่าฉันหมายถึงคลาสผู้ใช้
Marjan Venema

2
@GlenPeterson ปิดหัวข้อทั้งหมด แต่ฟังก์ชั่นการแฮชและการเข้ารหัสหลายรอบจะทำให้ข้อมูลอ่อนแอลง
Gusdor

3
@MarjanVenema: ฉันไม่ได้ตั้งใจยาก ฉันคิดว่าเรามีมุมมองที่แตกต่างกันมากและฉันต้องการที่จะเข้าใจคุณดีขึ้น ฉันได้เปิดคำถามใหม่ที่สามารถพูดคุยได้ดีกว่านี้: programmers.stackexchange.com/questions/216443/…
GlenPeterson

6

หากภาษาที่คุณเลือกไม่ผ่านโครงสร้างตามค่า(User user)ตัวแปรก็ดูดีกว่า ถ้าวันหนึ่งคุณตัดสินใจที่จะลบชื่อผู้ใช้และใช้ ID / รหัสผ่านเพื่อระบุผู้ใช้

นอกจากนี้วิธีการนี้ยังนำไปสู่การเรียกใช้เมธอดที่ยาวนานและเกินกำหนดหรือไม่สอดคล้องกัน การผ่าน 3 ข้อโต้แย้งตกลงไหม แล้วประมาณ 5 ล่ะ หรือ 6 ทำไมคิดอย่างนั้นถ้าผ่านวัตถุมีราคาถูกในแง่ของทรัพยากร (แม้ราคาถูกกว่าผ่านข้อโต้แย้ง 3 อาจ)?

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

ดังนั้นหากผ่านUserวัตถุจะส่งผลให้มีการคัดลอกโครงสร้างขนาดใหญ่วิธีแรกคือสะอาดและมีเหตุผลมากขึ้นกับฉัน


3

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

หากในภายหลังฉันต้องเปลี่ยนกฎการตรวจสอบฉันจะเขียนฟังก์ชันส่วนตัวใหม่พร้อมลายเซ็นใหม่ที่เรียกโดยภายนอก

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

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

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


ฉันไม่เห็นเหตุผลสำหรับวิธีการส่วนตัว ทำไมต้องรักษาทั้งสอง หากวิธีการส่วนตัวต้องการอาร์กิวเมนต์ที่แตกต่างกันคุณยังจะต้องแก้ไขพับลิก และคุณจะทดสอบผ่านทางสาธารณะ และไม่เป็นเรื่องปกติที่คุณต้องการทั้งสองอย่างในภายหลัง คุณคาดเดาได้ที่นี่ - YAGNI
Piotr Perak

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

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

คำอื่น: ฉันจะไม่ทดสอบหน่วยวิธีภายในผ่านหน่วยภายนอก นั่นเป็นวิธีทดสอบที่ไม่ดี
kriss

1
นี่เป็นวิธีปฏิบัติที่ดีและมีชื่อสำหรับมัน มันเรียกว่า "หลักการความรับผิดชอบเดี่ยว" มันสามารถนำไปใช้กับทั้งชั้นเรียนและวิธีการ การมีวิธีการที่มีความรับผิดชอบเพียงอย่างเดียวเป็นวิธีที่ดีในการสร้างรหัสแบบแยกส่วนและบำรุงรักษาได้มากขึ้น ในกรณีนี้งานหนึ่งคือการเลือกชุดข้อมูลพื้นฐานจากวัตถุผู้ใช้และงานอื่นกำลังตรวจสอบชุดข้อมูลพื้นฐานเพื่อดูว่าผู้ใช้เป็นผู้ดูแลระบบหรือไม่ โดยทำตามหลักการนี้คุณจะได้รับโบนัสในการเขียนวิธีการและหลีกเลี่ยงการทำซ้ำรหัส ซึ่งหมายความว่าตามที่ระบุไว้โดย @kriss ว่าคุณจะได้รับการทดสอบหน่วยที่ดีขึ้น
diegoreymendez

3

มีอยู่คนหนึ่งจุดลบที่จะส่งเรียน (ประเภทอ้างอิง) วิธีการเป็นและนั่นคือมวลของ USPTO ช่องโหว่ ลองจินตนาการว่าแทนที่จะเป็นIsAdmin(User user)วิธีฉันมีUpdateUser(User user)วิธี

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


2

ฉันจะไปกับวิธีนี้:

public bool IsAdmin(this IUser user) { /* ... */ }

public class User: IUser { /* ... */ }

public interface IUser
{
    string Username {get;}
    string Password {get;}
    IID Id {get;}
}
  • การใช้ประเภทอินเตอร์เฟสเป็นพารามิเตอร์สำหรับฟังก์ชั่นนี้ช่วยให้คุณส่งผ่านวัตถุผู้ใช้เพื่อกำหนดวัตถุจำลองผู้ใช้สำหรับการทดสอบและให้ความยืดหยุ่นแก่คุณมากขึ้นในการใช้และบำรุงรักษาฟังก์ชั่นนี้

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

  • ฉันใช้อินเทอร์เฟซที่กำหนดเองIIDแทนที่จะintเป็นเช่นนี้ช่วยให้คุณกำหนดคุณสมบัติของ ID ของคุณ; เช่นเคยคุณควรจะต้องเปลี่ยนจากintการlong, Guidหรือสิ่งอื่น นั่นอาจเกินความจริง แต่ก็เป็นการดีที่จะพยายามทำให้สิ่งต่าง ๆ มีความยืดหยุ่นเช่นที่คุณไม่ได้ถูกล็อคไว้ก่อนการตัดสินใจ

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


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

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

@Peri คลาสผู้ใช้จริงอาจมีความซับซ้อนในการสร้างการใช้อินเทอร์เฟซช่วยให้คุณเยาะเย้ยออกมาเพื่อให้คุณสามารถทดสอบได้ง่าย
jk

@JohnLBevan: YAGNI !!!
Piotr Perak

@jk: ถ้ามันยากที่จะสร้างผู้ใช้มีบางอย่างผิดปกติ
Piotr Perak

1

ปฏิเสธความรับผิดชอบ:

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

ฉันยังพิจารณาที่จะเทียบเท่ากับuser.isAdmin() IsAdmin(User user)นั่นเป็นตัวเลือกสำหรับคุณที่จะทำ

ตอบ:

คำแนะนำของฉันคือสำหรับผู้ใช้เท่านั้น:

public bool IsAdmin(User user);

หรือใช้ทั้งคู่ตามแนวของ:

public bool IsAdmin(User user); // calls the private method below
private bool IsAdmin(int id, string name, string password);

เหตุผลสำหรับวิธีการสาธารณะ:

เมื่อเขียนวิธีการสาธารณะมักจะเป็นความคิดที่ดีที่จะคิดเกี่ยวกับวิธีการใช้

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

เหตุผลสำหรับวิธีการส่วนตัว:

วิธีส่วนตัวที่ได้รับชุดพารามิเตอร์ที่ต้องการขั้นต่ำอาจเป็นสิ่งที่ดีในบางครั้ง บางครั้งก็ไม่มาก

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

public bool IsAdmin(Localuser user); // Just call private method
public bool IsAdmin(RemoteUser user); // Check if setting is on, then call private method
private bool IsAdmin(int id, string name, string password);

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

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


0
public bool IsAdmin(int id, string name, string password);

ไม่ดีสำหรับเหตุผลที่ระบุไว้ นั่นไม่ได้หมายความว่า

public bool IsAdmin(User user);

เป็นสิ่งที่ดีโดยอัตโนมัติ โดยเฉพาะอย่างยิ่งถ้าผู้ใช้เป็นวัตถุที่มีวิธีการเช่น: getOrders(), getFriends(), getAdresses()...

คุณอาจพิจารณา refactoring โดเมนที่มีประเภท UserCredentials ที่มี id ชื่อรหัสผ่านและส่งผ่านไปยัง IsAdmin แทนข้อมูลผู้ใช้ที่ไม่จำเป็นทั้งหมด

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