ทำใหม่ฟังก์ชั่นกลับรหัสจำนวนเต็มที่แสดงถึงสถานะที่แตกต่างกัน


10

ฉันได้รับรหัสอันยิ่งใหญ่ที่ฉันได้รวมตัวอย่างสั้น ๆ ของด้านล่าง

  • มีชื่อสำหรับรูปแบบการต่อต้านนี้โดยเฉพาะหรือไม่?
  • มีคำแนะนำอะไรบ้างสำหรับการปรับโครงสร้างนี้

    // 0=Need to log in / present username and password
    // 2=Already logged in
    // 3=Inactive User found
    // 4=Valid User found-establish their session
    // 5=Valid User found with password change needed-establish their session
    // 6=Invalid User based on app login
    // 7=Invalid User based on network login
    // 8=User is from an non-approved remote address
    // 9=User account is locked
    // 10=Next failed login, the user account will be locked
    
    public int processLogin(HttpServletRequest request, HttpServletResponse response, 
                            int pwChangeDays, ServletContext ServContext) { 
    }
    

2
อะไรคือ"พบสร้าง"และ"จำเป็นต้องสร้าง" ?
Tulains Córdova

4
ที่ควรจะเป็นประ emอ่านเช่น "พบผู้ใช้ที่ถูกต้อง: สร้างเซสชั่นของพวกเขา"
BJ Myers

2
@A_B ค่าใดที่ส่งคืนคือการเข้าสู่ระบบที่สำเร็จซึ่งล้มเหลวในการเข้าสู่ระบบ ไม่ทุกคนเห็นได้ชัดด้วยตนเอง
Tulains Córdova

@A_B "สร้างเซสชัน" หมายถึง "เซสชัน stablished" หรือ "ต้องการสร้างเซสชัน" หรือไม่
Tulains Córdova

@ TulainsCórdova: "Establish" หมายถึง "สร้าง" (อย่างน้อยก็ในบริบทนี้) - ดังนั้น "สร้างเซสชั่นของพวกเขา" มีค่าประมาณเท่ากับ "สร้างเซสชั่น"
hoffmale

คำตอบ:


22

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

ฉันอยากจะแนะนำ refactoring ต่อไปนี้: คืนค่า enum ด้วยผลลัพธ์ที่เป็นไปได้ (ตามที่แนะนำในคำตอบอื่น ๆ ) แต่เพิ่มคุณสมบัติ enum ที่ระบุว่าเป็นการปฏิเสธการสละสิทธิ์ (ฉันจะให้คุณผ่านครั้งสุดท้ายนี้) หรือ ถ้ามันตกลง (PASS):

public LoginResult processLogin(HttpServletRequest request, HttpServletResponse response, 
                            int pwChangeDays, ServletContext ServContext) { 
    }

==> LoginResult.java <==

public enum LoginResult {
    NOT_LOGGED_IN(Severity.DENIAL),
    ALREADY_LOGGED_IN(Severity.PASS),
    INACTIVE_USER(Severity.DENIAL),
    VALID_USER(Severity.PASS),
    NEEDS_PASSWORD_CHANGE(Severity.WAIVER),
    INVALID_APP_USER(Severity.DENIAL),
    INVALID_NETWORK_USER(Severity.DENIAL),
    NON_APPROVED_ADDRESS(Severity.DENIAL),
    ACCOUNT_LOCKED(Severity.DENIAL),
    ACCOUNT_WILL_BE_LOCKED(Severity.WAIVER);

    private Severity severity;

    private LoginResult(Severity severity) {
        this.severity = severity;
    }

    public Severity getSeverity() {
        return this.severity;
    }
}

==> Severity.java <==

public enum Severity {
    PASS,
    WAIVER,
    DENIAL;
}

==> Test.java <==

public class Test {

    public static void main(String[] args) {
        for (LoginResult r: LoginResult.values()){
            System.out.println(r + " " +r.getSeverity());           
        }
    }
}

เอาต์พุตสำหรับ Test.java แสดงความรุนแรงของแต่ละ LoginResult:

NOT_LOGGED_IN : DENIAL
ALREADY_LOGGED_IN : PASS
INACTIVE_USER : DENIAL
VALID_USER : PASS
NEEDS_PASSWORD_CHANGE : WAIVER
INVALID_APP_USER : DENIAL
INVALID_NETWORK_USER : DENIAL
NON_APPROVED_ADDRESS : DENIAL
ACCOUNT_LOCKED : DENIAL
ACCOUNT_WILL_BE_LOCKED : WAIVER

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

แก้ไข:

เพื่อเป็นการตอบสนองต่อความคิดเห็นของ @ T.Sar ฉันได้เปลี่ยนค่าที่เป็นไปได้ของความรุนแรงเป็น PASS, WAIVER และ DENIAL แทน (ตกลง, คำเตือนและข้อผิดพลาด) วิธีนี้เป็นที่ชัดเจนว่า DENIAL (ข้อผิดพลาดก่อนหน้านี้) ไม่ใช่ข้อผิดพลาดต่อ se และไม่จำเป็นต้องแปลเป็นการโยนข้อยกเว้น โทรตรวจสอบวัตถุและตัดสินใจหรือไม่ที่จะโยนยกเว้น processLogin(...)แต่ปฏิเสธสถานะผลที่ถูกต้องที่เกิดจากการโทร

  • ผ่าน:ไปข้างหน้าสร้างเซสชันหากยังไม่มี
  • การสละสิทธิ์:ไปข้างหน้าในครั้งนี้ แต่ผู้ใช้ครั้งต่อไปคุณอาจไม่ได้รับอนุญาตให้ผ่าน
  • ปฏิเสธ:ขออภัยผู้ใช้ไม่สามารถผ่านได้อย่าสร้างเซสชัน

คุณยังสามารถสร้าง enum "ซับซ้อน" (enum พร้อมแอตทริบิวต์) เพื่อฝังระดับของข้อผิดพลาดใน Enum อย่างไรก็ตามโปรดระวังเพราะถ้าคุณใช้เครื่องมือการทำให้เป็นอนุกรม somme มันอาจจะผ่านได้ไม่ดีนัก
Walfrat

การทิ้งข้อยกเว้นในกรณีข้อผิดพลาดและการบันทึก enums เพื่อความสำเร็จเท่านั้นก็เป็นตัวเลือกเช่นกัน
T. Sar

@ T.Sar ดีที่ฉันเข้าใจว่าพวกเขาไม่ใช่ข้อผิดพลาดต่อ se แต่ปฏิเสธที่จะสร้างเซสชั่นด้วยเหตุผลบางอย่าง ฉันจะแก้ไขคำตอบ
Tulains Córdova

@ T.Sar ฉันเปลี่ยนค่าเป็น PASS, WAIVER และ DENIAL เพื่อให้ชัดเจนว่าสิ่งที่ฉันเรียกว่า ERROR นั้นเป็นสถานะที่ถูกต้อง บางทีตอนนี้ฉันน่าจะได้ชื่อที่ดีกว่าสำหรับSeverity
Tulains Córdova

ฉันกำลังคิดถึงสิ่งอื่นด้วยคำแนะนำของฉัน แต่ฉันชอบข้อเสนอแนะของคุณจริงๆ! ฉันกำลัง +1 +1 อย่างแน่นอน!
ต. Sar

15

นี่คือตัวอย่างของการครอบงำแบบดั้งเดิม - การใช้ประเภทดั้งเดิมสำหรับงาน "ง่าย" ซึ่งในที่สุดก็ไม่ง่ายนัก

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

การรีแฟคเตอร์ทั่วไปสำหรับปัญหานี้คือการสร้างคลาส / struct / enum / object / ใหม่ใด ๆ ที่สามารถแสดงค่าในคำถามได้ดีขึ้น ในกรณีนี้คุณอาจพิจารณาเปลี่ยนเป็นเงื่อนไขenumที่มีผลหรือแม้กระทั่งคลาสที่สามารถมีboolเพื่อความสำเร็จหรือล้มเหลวข้อความแสดงข้อผิดพลาดข้อมูลเพิ่มเติม ฯลฯ

สำหรับข้อมูลเพิ่มเติม refactoring รูปแบบที่อาจเป็นประโยชน์มีลักษณะที่อุตสาหกรรมลอจิกของกลิ่นจะ refactorings Cheatsheet


7

ฉันจะเรียกว่ากรณีของ "หมายเลขวิเศษ" - หมายเลขที่พิเศษและไม่มีความหมายที่ชัดเจนด้วยตัวเอง

การเปลี่ยนโครงสร้างที่ฉันจะใช้ในที่นี้คือการปรับโครงสร้างประเภทส่งคืนเป็น enum เนื่องจากมันจะสรุปความกังวลของโดเมนในรูปแบบ การจัดการกับข้อผิดพลาดในการคอมไพล์หลุดออกมาจากนั้นควรจะเป็นชิ้นเล็ก ๆ น้อย ๆ ตั้งแต่ java enums สามารถสั่งซื้อและหมายเลข แม้ว่าจะไม่เป็นเช่นนั้นก็ไม่ควรที่จะจัดการกับพวกเขาโดยตรงแทนที่จะกลับไปสู่ ​​ints


นั่นไม่ใช่สิ่งที่มักจะหมายถึง 'หมายเลขเวทมนตร์'
D Drmmr

2
มันจะแสดงเป็นหมายเลขมายากลที่ไซต์การโทรเช่นเดียวกับในif (processLogin(..) == 3)
Daenyth

@Drmmr - นี่คือสิ่งที่มีความหมายโดยกลิ่นรหัส 'หมายเลขเวทมนตร์' ฟังก์ชั่นลายเซ็นนี้เกือบจะแน่นอนว่า processLogin () มีบรรทัดเช่น "return 8;" ในการนำไปใช้และมันก็บังคับให้ใช้โค้ดโดยใช้ processLogin () เพื่อให้มีลักษณะเช่นนี้ "if (resultFromProcessLogin == 7) {"
สตีเฟ่นซี. เหล็ก

3
@Stephen มูลค่าที่แท้จริงของตัวเลขไม่เกี่ยวข้องที่นี่ พวกเขาเป็นเพียงรหัส คำวิเศษหมายเลขมักจะใช้สำหรับค่าในรหัสที่มีความหมาย แต่ความหมายของใครคือไม่มีเอกสาร (เช่นในชื่อตัวแปร) การแทนที่ค่าที่นี่ด้วยตัวแปรจำนวนเต็มที่ตั้งชื่อจะไม่สามารถแก้ไขปัญหาได้
D Drmmr

2

นี่เป็นรหัสที่ไม่พึงประสงค์เป็นพิเศษ antipattern เรียกว่า "รหัสคืนเวทมนตร์" คุณสามารถค้นหาความคิดเห็นที่นี่

ค่าส่งคืนจำนวนมากระบุว่าสถานะข้อผิดพลาด มีการถกเถียงกันอย่างถูกต้องว่าจะใช้การจัดการข้อผิดพลาดสำหรับการควบคุมการไหล แต่ในกรณีของคุณฉันคิดว่ามี 3 กรณี: ความสำเร็จ (รหัส 4) ความสำเร็จ แต่ต้องเปลี่ยนรหัสผ่าน (รหัส 5) และ "ไม่อนุญาต" ดังนั้นหากคุณไม่สนใจการใช้ข้อยกเว้นสำหรับการควบคุมสายงานคุณสามารถใช้ข้อยกเว้นเพื่อระบุสถานะเหล่านั้นได้

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

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