If Else - Logika Kode Berulang

15

Bos saya memberi saya proyek dengan logika tertentu. Saya harus mengembangkan halaman web yang harus memimpin navigator melalui banyak kasus sampai dia tiba di produk.

Ini adalah skema jalur navigasi di situs:

Skema Jalur

PENTING!

Di halaman Produk, navigator dapat memilih filter mana yang diinginkan.

  • Jika A, dia HARUS melalui B (dan kemudian C tentu saja) atau C dan mencapai produk.
  • Jika B, ia harus melalui C dan mencapai produk.
  • Jika C, ia langsung mencapai produk.

Tentu saja jika saya mulai dari AI mengikuti jalur terpanjang dan ketika saya mencapai produk saya, saya memiliki 3 filter aktif.

Sampai sekarang saya mengembangkan kode berikut yang berfungsi dengan baik.

if filter_A
  if filter_B
     filter_C()
     .. else ..
  else
     filter_C
    .. else ..
else
   if filter_B
      filter_C()
     .. else ..
   else
     filter_C()
     .. else ..

Saya di sini untuk bertanya apa yang akan dilakukan oleh programmer yang lebih ahli dalam situasi ini. Saya tidak menghormati prinsip KERING, saya tidak suka dan saya ingin tahu cara alternatif untuk mengembangkan logika semacam ini.

Saya berpikir tentang memecah setiap bagian dari kode dalam fungsi tetapi apakah itu ide yang baik dalam kasus ini?

Kevin Cittadini
sumber
kemungkinan rangkap dari Kode Pengulangan dalam Pernyataan Kondisi
gnat
Diagram alir kontrol menunjukkan semua kontrol melalui filter_C, tetapi pernyataan bersyarat menunjukkan bahwa aliran kontrol dapat berputar filter_C. Apakah filter_Copsional?
CurtisHx
@CurtisHx Filter C wajib diisi. Ya maaf kesalahan saya, saya membuat copy-paste.
Kevin Cittadini
2
Bagaimana pertanyaan ini bisa menjadi agnostik bahasa ? Solusi idiomatik di Jawa akan sangat berbeda dari solusi idiomatik di Haskell. Apakah Anda belum memutuskan bahasa untuk proyek Anda?
200_success

Jawaban:

20

Anda belum mengatakan apakah filter mengambil parameter. Misalnya, filter_Amungkin filter kategori, jadi itu bukan hanya pertanyaan "apakah saya harus menerapkan filter_A", itu bisa "saya perlu menerapkan filter_Adan mengembalikan semua catatan dengan bidang kategori = fooCategory".

Cara paling sederhana untuk mengimplementasikan apa yang telah Anda jelaskan (tapi pastikan untuk membaca bagian kedua dari jawaban di bawah) mirip dengan jawaban yang lain, tetapi saya tidak akan mendapatkan boolean sama sekali. Saya akan mendefinisikan interface: FilterA, FilterB, FilterC. Maka Anda dapat memiliki sesuatu seperti (Saya seorang programmer Java, jadi ini akan menjadi sintaks Java-esque):

class RequestFilters {
    FilterA filterA;
    FilterB filterB;
    FilterC filterC;
}

Maka Anda dapat memiliki sesuatu seperti ini (menggunakan pola enum singleton dari Java Efektif ):

enum NoOpFilterA implements FilterA {
    INSTANCE;

    public List<Item> applyFilter(List<Item> input) {
       return input;
    }
}

Tetapi jika Anda benar-benar ingin beberapa item difilter, Anda bisa memberikan contoh FilterAimplementasi yang benar-benar melakukan sesuatu. Metode penyaringan Anda akan menjadi sangat sederhana

List<Item> filterItems(List<Item> data, RequestFilters filters) {
    List<Item> returnedList = data;
    returnedList = filters.filterA.filter(data);
    returnedList = filters.filterB.filter(data);
    returnedList = filters.filterC.filter(data);
    return returnedList;
}

Tapi saya baru memulai.

Saya menduga bahwa applyFilterpanggilan itu sebenarnya akan sangat mirip untuk ketiga jenis filter. Jika itu masalahnya, saya bahkan tidak akan melakukannya dengan cara yang dijelaskan di atas. Anda bisa mendapatkan kode yang lebih bersih dengan hanya memiliki satu antarmuka, lalu melakukan ini:

class ChainedFilter implements Filter {
     List<Filter> filterList;

     void addFilter(Filter filter) {
          filterList.add(filter);
     }

     List<Item> applyFilter(List<Item> input) {
         List<Item> returnedList = input;
         for(Filter f : filterList) {
             returnedList = f.applyFilter(returnedList);
         }
         return returnedList;
     }
}

Kemudian, saat pengguna Anda menavigasi halaman, Anda hanya menambahkan contoh baru dari filter apa pun yang Anda butuhkan saat yang tepat. Ini akan memungkinkan Anda untuk dapat menerapkan beberapa contoh dari filter yang sama dengan argumen yang berbeda jika Anda memerlukan perilaku itu di masa depan, dan juga menambahkan filter tambahan di masa depan tanpa harus mengubah desain Anda .

Selain itu, Anda dapat menambahkan sesuatu seperti di NoOpFilteratas atau Anda tidak bisa menambahkan filter tertentu sama sekali ke daftar, apa pun yang lebih mudah untuk kode Anda.

durron597
sumber
Terima kasih, karena Anda menemukan cara paling sederhana untuk mengubah logika tanpa mengubah kode juga. Ini membuat jawaban Anda yang terbaik. Saya akan menerapkan desain kode ini secepatnya
Kevin Cittadini
Jika Anda memiliki Anda Filtersebagai Predicatemaka Anda dapat menggunakannya secara langsung di StreamAPI. Banyak bahasa memiliki konstruksi fungsional yang serupa.
Boris the Spider
3
@ BoristheSpider Itu hanya jika dia menggunakan Java 8; dia bahkan tidak mengatakan bahasa apa yang dia gunakan. Bahasa lain memang memiliki konstruksi seperti itu tetapi saya tidak ingin membahas semua rasa berbeda tentang cara melakukannya
durron597
3
Dipahami - hanya layak disebutkan bahwa itu adalah jalan untuk dijelajahi jika OP ingin memberikan implementasi sebaik mungkin. Anda tentu memiliki +1 saya untuk jawaban yang sudah sangat bagus.
Boris the Spider
3

Dalam hal ini, penting untuk memisahkan logika pemfilteran, dan aliran kontrol tentang bagaimana filter berjalan. Logika filter harus dipisahkan menjadi fungsi-fungsi individual, yang dapat berjalan secara independen satu sama lain.

ApplyFilterA();
ApplyFilterB();
ApplyFilterC();

Dalam kode contoh diposting, ada 3 boolean filter_A, filter_Bdan filter_C. Namun, dari diagram, filter_Cselalu berjalan, sehingga dapat diubah menjadi tanpa syarat.

CATATAN: Saya berasumsi bahwa diagram alur kontrol sudah benar. Ada perbedaan antara kode sampel yang diposting dan diagram alir kontrol.

Sepotong kode terpisah mengontrol filter mana yang dijalankan

ApplyFilters(bool filter_A, bool filter_B)
{
    listOfProducts tmp;
    if (filter_A)
        ApplyFilterA();
    if (filter_B)
        ApplyFilterB();
    ApplyFilterC();
}

Ada pemisahan yang berbeda antara mengendalikan filter mana yang berjalan, dan apa yang dilakukan filter. Pisahkan kedua potongan logika itu.

CurtisHx
sumber
+1 Ini sepertinya jauh lebih sederhana dan terpisah daripada jawaban yang diterima.
winkbrace
2

Saya berasumsi, bahwa Anda menginginkan algoritma paling sederhana dan paling jelas.
Dalam hal ini, mengetahui bahwa filter c selalu diterapkan, saya akan menjalankannya dari logika if dan menerapkannya di akhir. Seperti yang terlihat dalam diagram alur Anda, setiap filter sebelum c, adalah opsional, karena masing-masingnya dapat diterapkan, atau tidak. Dalam hal ini, saya akan hidup seandainya terpisah dari setiap filter, tanpa bersarang dan merantai:

if filter_a
  do_filter_a()

if filter_b
  do_filter_b()

do_filter_c()

jika Anda memiliki diagram alur dengan sejumlah variabel filter, sebelum yang wajib, saya akan, sebagai gantinya, menyimpan semua filter ke array, dalam urutan yang akan muncul. Kemudian proses filter opsional dalam loop dan terapkan yang wajib di akhir, di luar loop:

optional_filters_array = (a, b, c, d, e, f, g, h, etc)

for current_filter in optional_filters_array
  do_filter(current_filter)

do_required_filter()

atau:

optional_filters_array = (a, b, c, d, e, f, g, h, etc)
required_filter = last_filter


for current_filter in optional_filters_array
  do_filter(current_filter)

do_filter(required_filter)

keberanian, Anda harus mendefinisikan subrutin pemrosesan filter.

igoryonya
sumber
1

Saya akan menganggap filterA, filterB, dan filterC benar-benar mengubah daftar produk. Kalau tidak, jika mereka hanya jika-cek, maka filterA dan filterB dapat diabaikan karena semua jalur akhirnya mengarah ke filterC. Deskripsi Anda tentang persyaratan tampaknya menyiratkan bahwa setiap filter akan mengurangi daftar produk.

Jadi dengan asumsi filter benar-benar mengurangi daftar produk, inilah sedikit pseudo-code ...

class filter
    func check(item) returns boolean
endclass

func applyFilter(filter, productList) returns list
    newList is list
    foreach item in productList
        if filter.check(item) then
            add item to newList
        endif
    endfor 
    return newList
endfunc



filterA, filterB, filterC = subclasses of filter for each condition, chosen by the user
products = list of items to be filtered

if filterA then
    products = applyFilter(filterA, products)
endif

if filterB then
    products = applyFilter(filterB, products)
endif

if filterC then
    products = applyFilter(filterC, products)
endif

# use products...

Dalam persyaratan Anda, filterC tidak diterapkan secara otomatis, tetapi dalam diagram, itu. Jika persyaratannya adalah setidaknya filterC harus diterapkan tidak peduli apa pun, maka Anda akan memanggil applyFilter (filterC, produk) tanpa memeriksa apakah filterC dipilih.

filterC = instance of filter, always chosen

...

# if filterC then
products = applyFilter(filterC, products)
# endif
Kent A.
sumber
0

Saya ingin tahu apakah pemodelan filter Anda menjadi semacam objek dalam grafik akan masuk akal. Setidaknya itulah yang saya pikirkan ketika melihat diagram.

Jika Anda memodelkan ketergantungan filter seperti grafik objek, maka kode yang menangani jalur aliran yang mungkin cukup lurus ke depan tanpa logika berbulu. Juga, grafik (logika bisnis) dapat berubah, sedangkan kode yang menginterpretasikan grafik tetap sama.

enum
sumber