Else - Tekrarlanan Kod Mantığı


15

Patronum bana belirli bir mantığı olan bir proje verdi. Ürüne gelene kadar navigatöre birçok durumda liderlik etmesi gereken bir web sayfası geliştirmem gerekiyor.

Bu, sitedeki gezinmenin yol şemasıdır:

Yol Şeması

ÖNEMLİ!

Ürünler sayfasında gezgin hangi filtreyi istediğini seçebilir.

  • A, o / o takdirde GEREKİR B geçmesi (ve sonra tabii C) veya C ve ürünleri ulaşır.
  • B ise, C'den geçmesi ve ürünlere ulaşması ZORUNLUDUR .
  • C ise doğrudan ürünlere ulaşır.

Tabii ki yapay zekadan başlıyorsam en uzun yolu takip ediyor ve ürünlerime ulaştığımda 3 aktif filtrem var.

Şimdiye kadar iyi çalışan aşağıdaki kodu geliştirdim.

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

Bu durumda daha uzman bir programcının ne yapması gerektiğini sormak için buradayım. KURU ilkesine saygı duymadım, hoşuma gitmedi ve bu tür bir mantığı geliştirmenin alternatif bir yolunu bilmek istiyorum.

Kodların her bölümünü işlevlerde bölmeyi düşündüm ama bu durumda iyi bir fikir mi?



Kontrol akış şeması, geçen tüm kontrolleri gösterir filter_C, ancak koşullu ifadeler kontrol akışının dolaşabileceğini gösterir filter_C. Mı filter_Copsiyonel?
CurtisHx

@CurtisHx Filtre C zorunludur. Evet üzgünüm hatam kopyala-yapıştır yaptım.
Kevin Cittadini

2
Bu soru dile agnostik nasıl olabilir ? Java'daki deyimsel çözüm, Haskell'deki deyimsel çözümden çok farklı olurdu. Projeniz için bir dile karar vermediniz mi?
200_success

Yanıtlar:


20

Filtrelerin herhangi bir parametre alıp almadığını söylemediniz. Örneğin, filter_Abir kategori filtresi olabilir, bu yüzden bu sadece "başvurmam gerekiyor mu" sorusu değil, " Tüm kategorileri = = = alanıyla birlikte tüm kayıtları filter_Auygulamam filter_Ave geri göndermem gerekiyor" sorusu olabilir fooCategory.

Tam olarak tanımladığınız şeyi uygulamanın en basit yolu (ancak aşağıdaki cevabın ikinci yarısını okuduğunuzdan emin olun) diğer cevaplara benzer, ancak herhangi bir boolean kontrolüm olmazdı. Ben arabirimleri tanımlarsınız: FilterA, FilterB, FilterC. Sonra bir şey olabilir (Ben bir Java programcısıyım, bu yüzden bu Java-esque sözdizimi olacak):

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

O zaman böyle bir şey (kullanarak olabilir enum Tekli yöntemin gelen Etkili Java ):

enum NoOpFilterA implements FilterA {
    INSTANCE;

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

Ancak, bazı öğelerin gerçekten filtrelenmesini istiyorsanız bunun yerine bir FilterAşey yapan bir uygulamanın örneğini sağlayabilirsiniz . Filtrasyon yönteminiz çok basit olacak

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

Ama daha yeni başlıyorum.

applyFilterÇağrının aslında her üç filtre türü için de oldukça benzer olacağından şüpheleniyorum . Eğer durum buysa, yukarıda anlatıldığı gibi yapmam bile. Sadece bir arayüze sahip ve daha sonra bunu yaparak daha temiz bir kod elde edebilirsiniz:

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

Ardından, kullanıcınız sayfalarda gezinirken, uygun olduğunda ihtiyacınız olan her filtre için yeni bir örnek eklersiniz. Bu, ileride bu davranışa ihtiyaç duymanız durumunda aynı filtrenin birden fazla örneğini farklı bağımsız değişkenlerle uygulayabilmenizi ve ayrıca tasarımınızı değiştirmek zorunda kalmadan gelecekte ek filtreler eklemenizi sağlar .

Ayrıca, NoOpFilteryukarıdaki gibi bir şey ekleyebilir veya kodunuz için daha kolay ne olursa olsun listeye belirli bir filtre ekleyemezsiniz.


Teşekkür ederim, çünkü kodu değiştirmeden mantığı değiştirmenin mümkün olan en basit yolunu buluyorsunuz. Bu, yanıtınızı en iyi hale getirir. Bu kod tasarımını en kısa zamanda uygulayacağım
Kevin Cittadini

İstemiyorsun, mutfakta annene olsaydı Filterbir şekilde Predicateo zaman doğrudan kullanabilirsin StreamAPI. Birçok dil benzer fonksiyonel yapılara sahiptir.
Örümcek Boris

3
@BoristheSpider Bu sadece Java 8 kullanıyorsa; hangi dili kullandığını bile söylemedi. Diğer dillerde böyle bir yapı var ama bunu nasıl yapacağımın tüm farklı tatlarına girmek istemedim
durron597

3
Anlaşıldı - OP'nin mümkün olan en temiz uygulamayı sağlamak isteyip istemediğini keşfetmek için bir yol olduğunu belirtmek gerekir. Zaten mükemmel bir cevap için + 1'im var.
Örümcek Boris

3

Bu durumda, filtreleme mantığını ve filtrelerin nasıl çalıştığının kontrol akışını ayırmak önemlidir. Filtre mantığı, birbirinden bağımsız olarak çalışabilen ayrı işlevlere ayrılmalıdır.

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

Yayınlanan örnek kodda, orada 3 Boolean var filter_A, filter_Bve filter_C. Ancak, şemadan, filter_Cher zaman çalışır, böylece koşulsuz olarak değiştirilebilir.

NOT: Kontrol akış şemasının doğru olduğunu varsayıyorum. Kaydedilen numune kodu ile kontrol akış diyagramı arasında bir tutarsızlık vardır.

Filtrelerin çalıştırıldığı ayrı bir kod denetimi parçası

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

Hangi filtrelerin çalıştığını ve filtrelerin ne yaptığını kontrol etmek arasında belirgin bir ayrım vardır. Şu iki mantığı parçalayın.


+1 Bu, kabul edilen cevaptan çok daha basit ve ayrıştırılmış görünüyor.
winkbrace

2

En basit, en açık algoritmayı istediğinizi varsayıyorum.
Bu durumda, c filtresinin her zaman uygulandığını bilerek, if mantığından çıkarır ve sonunda olursa olsun sonunda uygularım. Akış çizelgenizde göründüğü gibi, c'den önceki her filtre isteğe bağlıdır, çünkü her biri uygulanabilir veya uygulanamaz. Bu durumda, yuvalama ve zincirleme olmadan, her filtreden ayrı ifs yaşayacaktım:

if filter_a
  do_filter_a()

if filter_b
  do_filter_b()

do_filter_c()

zorunlu sayıdan önce değişken sayıda filtreye sahip bir akış şemanız varsa, bunun yerine, tüm filtreleri görünmeleri gereken sırayla bir diziye kaydederim. Ardından, döngüdeki isteğe bağlı filtreleri işleyin ve zorunlu olanı döngünün dışına uygulayın:

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

veya:

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)

Örneğin, filtre işleme altyordamını tanımlamanız gerekir.


1

FilterA, filterB ve filterC'nin aslında ürün listesini değiştireceğini varsayacağım. Aksi takdirde, eğer sadece kontroller ise, tüm yollar sonuçta filterC'ye götürdüğünden filterA ve filterB göz ardı edilebilir. Gereklilikle ilgili açıklamanız, her filtrenin ürün listesini azaltacağı anlamına geliyor.

Filtrelerin aslında ürün listesini azalttığı varsayılarak, burada sahte kod biraz ...

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...

Gereksinimlerinizde, filterC otomatik olarak uygulanmaz, ancak şemada uygulanır. Gereksinim, ne olursa olsun en azından filterC'nin uygulanması gerektiğinde, filterC'nin seçilip seçilmediğini kontrol etmeden ApplyFilter (filterC, ürünler) öğesini çağırırsınız.

filterC = instance of filter, always chosen

...

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

0

Filtrelerinizi bir grafikteki bir tür nesne olarak modellemenin mantıklı olup olmadığını merak ediyorum. En azından diyagramı gördüğümde böyle düşünüyorum.

Filtrelerin bağımlılığını bir nesne grafiği gibi modellerseniz, olası akış yollarını işleyen kod, kıllı bir mantık olmadan hemen hemen düzdür. Ayrıca, grafiği (iş mantığı) değişebilir, grafiği yorumlayan kod aynı kalır.

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.