Birçok farklı durumu temsil eden bir tamsayı kodu döndüren bir işlevi yeniden işleme


10

Aşağıda kısa bir örnek ekledim bazı kötü kod miras aldım.

  • Bu belirli anti-desen için bir isim var mı?
  • Bunu yeniden düzenlemek için bazı öneriler nelerdir?

    // 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
Ne edilmektedir "kurmak bulundu" ve "gerekli kurmak" ?
Tulains Córdova

4
Bunun bir kısa çizgi olması gerekiyordu , "geçerli kullanıcı bulundu: oturumlarını oluştur" gibi okunur.
BJ Myers

2
@A_B Bu dönüş değerlerinden hangisi başarılı girişler, hangisi başarısız girişler. Hepsi apaçık değildir.
Tulains Córdova

@A_B "Oturumlarını oluşturmak", "oturumun durgunlaştırılması" veya "oturumun durgunlaştırılması gerektiği" anlamına mı geliyor?
Tulains Córdova

@ TulainsCórdova: "Kur", "en azından bu bağlamda" oluşturmak ("en az bu bağlamda") anlamına gelir - bu nedenle "oturumlarını oluştur" kabaca "oturumlarını oluştur"
öğesine

Yanıtlar:


22

Kod sadece sihirli sayılardan dolayı kötü değil , aynı zamanda dönüş kodunda birkaç anlamı birleştirdiği için, anlamının içinde bir hata, bir uyarı, bir oturum oluşturma izni veya üçün bir kombinasyonunu gizleme anlamına gelir. karar vermede kötü girdi.

Aşağıdaki yeniden düzenleme önerebilirim: (diğer yanıtlarda önerildiği gibi) olası sonuçlarla bir enum döndürmek, ancak enum'a bir reddi, bir feragat olup olmadığını belirten bir özellik ekleyerek (son kez geçmenize izin vereceğim) veya eğer uygunsa (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;
    }
}

==> Önem Derecesi.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 için her bir Girişin önem derecesini gösteren çıktı

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

Hem numaralandırma değerine hem de önem derecesine göre, oturum oluşturmanın devam edip etmeyeceğine karar verebilirsiniz.

DÜZENLE:

@ T.Sar'ın yorumuna yanıt olarak, önem derecesinin olası değerlerini (OK, WARNING ve ERROR) yerine PASS, WAIVER ve DENIAL olarak değiştirdim. Bu şekilde o (daha önce HATA) bir İnkarı haddi zatında bir hata değildir ve olmamalıdır açıktır mutlaka bir istisna atma çevirmek. Arayan kişi nesneyi inceler ve istisna verip vermemeye karar verir, ancak DENIAL çağrı yapılmasından kaynaklanan geçerli bir sonuç durumudur processLogin(...).

  • PASS: Devam et, henüz yoksa bir oturum oluştur
  • FERAGAT: bu sefer devam et, ama bir dahaki sefere kullanıcının geçmesine izin verilmeyebilir
  • DENIAL: üzgünüm, kullanıcı geçemez, oturum oluşturma

Ayrıca, Enum'a hata düzeyini katıştırmak için bir "karmaşık" enum (özniteliklerle enum) oluşturabilirsiniz. Ancak dikkatli olun çünkü somme serileştirme araçlarını kullanırsanız bu çok iyi geçmeyebilir.
Walfrat

Hata durumlarında istisnaları atmak ve sıralamaları sadece başarı için kaydetmek de bir seçenektir.
T. Sar

@ T.Sar Anladığım kadarıyla, bunlar kendi başına hatalar değil, bir nedenle bir oturum oluşturmayı reddetti. Cevabı düzenleyeceğim.
Tulains Córdova

@ T.Sar Daha önce ERROR dediğim şeyin geçerli bir durum olduğunu açıkça belirtmek için değerleri PASS, WAIVER ve DENIAL olarak değiştirdim. Belki şimdi daha iyi bir isim Severity
bulmalıyım

Tavsiyemle başka bir şey düşünüyordum, ama önerinizi gerçekten beğendim! Kesinlikle +1 atarım!
T. Sar

15

Bu, İlkel Takıntıya bir örnektir - sonuçta o kadar basit olmayan "basit" görevler için ilkel türleri kullanmak.

Bu, boolbaşarı veya başarısızlığı belirtmek için a döndüren , daha sonra intüçüncü bir durum olduğunda bir döneme dönüşen ve nihayetinde hemen hemen belgelenmemiş hata koşullarının bir listesi haline gelen bir kod olarak başlamış olabilir .

Bu sorun için tipik yeniden düzenleme, söz konusu değeri daha iyi temsil edebilecek yeni bir sınıf / struct / enum / object / oluşturmaktır. Bu durumda, enumsonuç koşullarını içeren bir sınıra, hatta boolbaşarı veya başarısızlık için bir sınıfa , bir hata mesajına, ek bilgilere vb. Sahip bir sınıfa geçmeyi düşünebilirsiniz .

Yararlı olabilecek daha yeniden düzenleme modelleri için Industrial Logic'in Kokuları Yeniden Düzenleme Hileleri Sayfasına bir göz atın .


7

Buna "sihirli sayılar" denir - özel olan ve kendileri tarafından belirgin bir anlamı olmayan sayılar.

Burada uygulayacağım yeniden düzenleme, bir türdeki etki alanı endişesini kapsadığı için dönüş türünü bir numaralandırmaya yeniden yapılandırmaktır. Java enumları sipariş edilip numaralandırılabildiğinden, bundan çıkan derleme hatalarıyla başa çıkmak mümkün bir parça parça olmalıdır. Olmasa bile, ints'e geri dönmek yerine onlarla doğrudan uğraşmak zor olmamalıdır.


Genellikle 'sihirli sayılar' ile kastedilen bu değildir.
D Drmmr

2
Çağrı sitelerinde olduğu gibi sihirli numaralar olarak if (processLogin(..) == 3)
görünecek

@DDrmmr - Bu 'sihirli sayılar' kod kokusu ile kastedilen şeydir. Bu işlev imzası neredeyse kesin olarak processLogin () öğesinin "return 8;" uygular ve processLogin () kullanarak kodu "if (sonuçFromProcessLogin == 7) {" gibi bir şeye benzemeye zorlar.
Stephen C. Steel

3
@Stephen Sayıların gerçek değeri burada önemsizdir. Onlar sadece kimliklerdir. Terimi sihirli numaralar genellikle anlama sahip kodunda değerler için kullanılır, ama kim (örneğin bir değişken adı olarak) belgelenmemiş anlam oluyor. Buradaki değerlerin adlandırılmış tamsayı değişkenleriyle değiştirilmesi sorunu çözmez.
D Drmmr

2

Bu özellikle hoş olmayan bir kod parçasıdır. Antipattern "sihirli dönüş kodları" olarak bilinir. Burada bir tartışma bulabilirsiniz .

Dönüş değerlerinin çoğu hata durumlarını gösterir. Akış kontrolü için hata işleme kullanılıp kullanılmayacağına dair geçerli bir tartışma var, ancak sizin durumunuzda, 3 durum olduğunu düşünüyorum: başarı (kod 4), başarı ancak parolayı (kod 5) değiştirmeniz ve "izin verilmiyor". Dolayısıyla, akış denetimi için özel durumlar kullanmayı umursamıyorsanız, bu durumları belirtmek için özel durumlar kullanabilirsiniz.

Başka bir yaklaşım, başarılı bir giriş için "profil" ve "oturum" özniteliği, gerekirse "must_change_password" özniteliği ve günlüğün nedenini belirtmek için bir grup öznitelik içeren bir "kullanıcı" nesnesini döndürmek için tasarımı yeniden düzenlemek olacaktır. - akış bu olsaydı başarısız oldu.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.