Değer denetleyici işlevimin hem bir boole hem de bir ileti döndürmesi gerekiyor


14

Ben bir dize geçirilen ve değeri doğru biçimde olup olmadığını kontrol etmek için gereken bir değer kontrol fonksiyonu, bir kredi kartı numarası kontrol fonksiyonu gibi bir şey var.

Doğru biçimse, doğru dönmesi gerekir.

Doğru biçim değilse, false döndürmesi ve aynı zamanda değerle ilgili sorunun ne olduğunu bize bildirmesi gerekir.

Soru şu ki, bunu başarmanın en güzel yolu nedir?

İşte birkaç çözüm:

1. Anlamları belirtmek için tamsayı / numaralandırma dönüş kodlarını kullanın:

String[] returnCodeLookup = 
[
"Value contains wrong number of characters, should contain 10 characters",
"Value should end with 1", 
"Value should be a multiple of 3"
]

private int valueChecker(String value)
{
    /*check value*/
    return returnCode;
}

rc = checkValue(valueToBeChecked);
if rc == 0
{
    /*continue as normal*/
}
else
{
    print("Invalid value format: ") + returnCodeLookup[rc];
}

Bu çözümü sevmiyorum, çünkü işlerin arayan tarafında uygulama gerektiriyor.

2. Bir returnCode sınıfı oluşturun

Class ReturnCode()
{
    private boolean success;
    private String message;

    public boolean getSuccess()
    {
        return this.success;
    }

    public String getMessage()
    {
        return this.message; 
    }
}

private ReturnCode valueChecker(String value)
{
    /*check value*/
    return returnCode;
}

rc = checkValue(valueToBeChecked);
if rc.getSuccess()
{
    /*continue as normal*/
}
else
{
    print("Invalid value format: ") + rc.getMessage();
}

Bu çözüm düzenli, ancak tekerleği aşırı doldurmak / yeniden icat etmek gibi görünüyor.

3. İstisnalar kullanın.

private boolean valueChecker(String value)
{
    if int(value)%3 != 0 throw InvalidFormatException("Value should be a multiple of 3";
    /*etc*/
    return True;
}

try {
rc = checkValue(valueToBeChecked);
}

catch (InvalidFormatException e)
{
     print e.toString();
}

Bu çözümü kullanmak için cazipim, ancak iş mantığı için istisnalar kullanmamanız gerektiği söylendi.


'[..] değerin doğru biçimde olup olmadığını kontrol et.' Öyleyse adı FormatChecker olmamalı mı ?
Andy

Doğru / yanlış sonuç gereksiz görünüyor. Başarıyı belirtmek için boş veya boş bir String döndürebilir mi? UNIX için yaklaşık 50 yıl çalıştı. :-)
user949300

Yanıtlar:


14

Her iki endişeyi de içine alan daha karmaşık bir dönüş nesnesi kullanın. Misal:

public interface IValidationResult {
  boolean isSuccess();
  String getMessage();
}

Bunun birkaç avantajı vardır:

  1. Bir nesnede birden çok ilişkili veri parçasını döndürür.
  2. Gelecekte ek veri eklemeniz gerekirse genişleme için yer açın.
  3. Geçici bağlantıya güvenilmez: birden fazla girişi doğrulayabilirsiniz ve diğer cevaptaki gibi mesajı engellemezler. İletileri herhangi bir sırayla, hatta ileti dizileri arasında kontrol edebilirsiniz.

Bu özel tasarımı daha önce, bir doğrulamanın sadece doğru veya yanlıştan daha fazla olabileceği uygulamalarda kullanmıştım. Belki de ayrıntılı bir mesaj gereklidir veya girdinin yalnızca bir kısmı geçersizdir (örneğin, on öğeli bir formda yalnızca bir veya iki geçersiz alan olabilir). Bu tasarımı kullanarak bu gereksinimleri kolayca karşılayabilirsiniz.


İtiraf etmeliyim ki bu çözüm benimkinden daha iyi. Benimki güvenli değil.
Tulains Córdova

@ user61852 Bu bir sonuç nesnesi için bir arabirimin yüksek düzeyde genel bir bakış olsa da, burada amaç doğrulama kodunun durum içermeyen kendi nesnesi olacağını düşünüyorum. Bu, değişmez hale getirir, bu sitede defalarca konuştuğumuz birçok faydası vardır.

Arayüz neden gereklidir?
dwjohnston

1
@dwjohnston bir arayüz gerekli değildir, ancak iyi bir fikirdir. Kalıtım, yalnızca gerektiğinde kullanılması gereken çok güçlü bir bağlantı türüdür.

Alternatif olarak, daha da basitleştirebilirsiniz. Başarı ilginç değil, bu yüzden IValidationResult.SUCCESSboş bir hata mesajı döndüren bir sabit bildirin. Sonra mantığınız şöyle görünürif (result != SUCCESS) { doStuff(result.getMessage()); }
Morgen

2

Yukarıdakilerin hiçbiri, bir ValueChecker sınıfı kullanmayın

İlk olarak size esneklik sağlayan bir arayüz:

public interface IValueChecker {
    public boolean checkValue(String value);
    public String getLastMessage();
}

Ardından, ihtiyacınız olduğu kadar çok değerli denetleyici uygulayın:

public class MyVeryEspecificValueChecker implements IValueChecker {
    private String lastMessage="";
    @Override
    public boolean checkValue(String value) {
        boolean valid=false;
        // perform check, updates "valid" and "lastMessage"
        return valid;
    }
    @Override
    public String getLastMessage() {
        return lastMessage;
    }
}

Örnek müşteri kodu:

public class TestValueChecker {
    public static void main(String[] args) {
        String valueToCheck="213123-YUYAS-27163-10";
        IValueChecker vc = new MyVeryEspecificValueChecker();
        vc.checkValue(valueToCheck);
        System.out.println(vc.getLastMessage());
    }
}

Birçok farklı değer denetleyicisine sahip olmanız avantajına sahiptir.


1
Ben kontrol son değeri görmek için bir yol olmadan, değer denetleyicisi tutma durumunu gibi emin değilim.
Peter

1

Cevabım @ Snowman'ın yaklaşımını genişletiyor. Temel olarak, her doğrulama, her iş kuralı ve her iş mantığı, en azından web uygulamalarında bazı yanıtlara yol açabilmelidir. Bu yanıt sırayla bir arayan kişiye gösterilir. Bu beni aşağıdaki arayüze getirdi (php, ancak soru doğada dil bilincine sahip değil):

interface Action
{
    /**
     * @param Request $request
     * @throws RuntimeException
     * @return Response
     */
    public function act(Request $request);
}

İfade gibi değil, bir ifade gibi davranan anahtar operatörü oluşturmak, uygulama hizmetinin şöyle görünmesine yol açar:

class MyApplicationService implements Action
{
    private $dataStorage;

    public function __construct(UserDataStorage $dataStorage)
    {
        $this->dataStorage = $dataStorage;
    }

    public function act(Request $request)
    {
        return
            (new _SwitchTrue(
                new _Case(
                    new EmailIsInvalid(),
                    new EmailIsInvalidResponse()
                ),
                new _Case(
                    new PasswordIsInvalid(),
                    new PasswordIsInvalidResponse()
                ),
                new _Case(
                    new EmailAlreadyRegistered($this->dataStorage),
                    new EmailAlreadyRegisteredResponse()
                ),
                new _Default(
                    new class implements Action
                    {
                        public function act(Request $request)
                        {
                            // business logic goes here

                            return new UserRegisteredResponse();
                        }
                    }
                )
            ))
                ->act($request)
            ;
    }
}
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.