Fungsi pemeriksa nilai saya perlu mengembalikan boolean dan pesan

14

Saya memiliki fungsi pengecekan nilai, mirip dengan fungsi pengecekan nomor kartu kredit, yang diteruskan dalam sebuah string, dan perlu memeriksa bahwa nilainya dalam format yang tepat.

Jika itu format yang benar, ia perlu mengembalikan true.

Jika itu bukan format yang benar, ia perlu mengembalikan false, dan juga memberi tahu kami apa yang salah dengan nilainya.

Pertanyaannya adalah, apa cara terbaik untuk mencapai ini?

Inilah beberapa solusi:

1. Gunakan kode integer / enum return untuk menandakan makna:

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];
}

Saya tidak suka solusi ini karena membutuhkan implementasi di sisi penelepon.

2. Buat kelas returnCode

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();
}

Solusi ini rapi, tetapi sepertinya membutuhkan banyak tenaga / menciptakan kembali roda.

3. Gunakan pengecualian.

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();
}

Saya tergoda untuk menggunakan solusi ini, tetapi saya diberitahu bahwa Anda tidak boleh menggunakan pengecualian untuk logika bisnis.

djohnston
sumber
'[..] periksa apakah nilainya dalam format yang tepat.' Bukankah seharusnya namanya FormatChecker ?
Andy
Hasil benar / salah tampak berlebihan. Bisakah itu hanya mengembalikan String kosong atau nol untuk menunjukkan keberhasilan? Itu bekerja untuk UNIX selama sekitar 50 tahun. :-)
user949300

Jawaban:

14

Gunakan objek pengembalian yang lebih kompleks yang merangkum kedua masalah. Contoh:

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

Ini memiliki beberapa keunggulan:

  1. Mengembalikan beberapa data terkait dalam satu objek.
  2. Ruang untuk ekspansi jika Anda perlu menambahkan data tambahan di masa mendatang.
  3. Tidak ada ketergantungan pada penggabungan temporal: Anda dapat memvalidasi beberapa input dan mereka tidak menolak pesan seperti pada jawaban lainnya. Anda dapat memeriksa pesan dalam urutan apa pun, bahkan di utas.

Saya sebenarnya telah menggunakan desain khusus ini sebelumnya, dalam aplikasi di mana validasi mungkin lebih dari sekadar benar atau salah. Mungkin diperlukan pesan terperinci, atau hanya sebagian dari input tidak valid (mis. Formulir dengan sepuluh elemen mungkin hanya memiliki satu atau dua bidang yang tidak valid). Dengan menggunakan desain ini, Anda dapat dengan mudah mengakomodasi persyaratan tersebut.


sumber
Saya harus mengakui bahwa solusi ini lebih baik daripada solusi saya. Milik saya bukan threadsafe.
Tulains Córdova
@ user61852 Meskipun ini adalah ikhtisar tingkat tinggi dari antarmuka untuk objek hasil, saya pikir tujuannya di sini adalah bahwa kode validasi akan menjadi objeknya sendiri yang tidak mengandung keadaan. Itu akan membuatnya tidak berubah, yang memiliki banyak manfaat yang kita bicarakan berulang kali di situs ini.
Mengapa diperlukan antarmuka?
dwjohnston
1
@dwjohnston antarmuka tidak diperlukan, tapi itu ide yang bagus. Warisan adalah jenis kopling yang sangat kuat yang seharusnya hanya digunakan jika perlu.
Sebagai alternatif, Anda dapat menyederhanakan lebih lanjut. Sukses tidak menarik, jadi nyatakan konstanta IValidationResult.SUCCESSyang mengembalikan pesan kesalahan kosong. Maka logika Anda terlihat sepertiif (result != SUCCESS) { doStuff(result.getMessage()); }
Morgen
2

Tidak ada yang di atas, gunakan kelas ValueChecker

Pertama sebuah antarmuka untuk memberi Anda fleksibilitas:

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

Kemudian laksanakan sebanyak mungkin penilai yang Anda butuhkan:

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;
    }
}

Contoh kode klien:

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());
    }
}

Ini memiliki keuntungan bahwa Anda dapat memiliki banyak checker nilai yang berbeda.

Tulains Córdova
sumber
1
Saya tidak yakin saya menyukai status menjaga pemeriksa nilai, tanpa memiliki cara untuk melihat nilai terakhir diperiksa.
Peter K.
1

Jawaban saya memperluas pendekatan Snowman. Pada dasarnya, setiap validasi, setiap aturan bisnis, dan setiap logika bisnis harus dapat menghasilkan beberapa respons - setidaknya, dalam aplikasi web. Respons ini, pada gilirannya, ditampilkan kepada penelepon. Ini membawa saya ke antarmuka berikut (ini adalah php, tetapi pertanyaannya pada dasarnya adalah bahasa-agnostik):

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

Membuat switch operator yang bertindak seperti ekspresi, bukan seperti pernyataan, mengarah ke layanan aplikasi yang terlihat seperti itu:

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)
            ;
    }
}
Zapadlo
sumber