Model ve görünümle uğraşırken polimorfizme karşı geçiş


12

Sorunum için daha iyi bir çözüm bulamıyorum. Öğelerin listesini sunan bir görünüm denetleyicim var. Bu öğeler, B, C, D vb.'nin bir örneği olabilen ve A'dan devralınabilen modellerdir. Bu nedenle, bu görünüm denetleyicisinde, her öğe uygulamanın farklı bir ekranına gitmeli ve kullanıcı bunlardan birini seçtiğinde bazı verileri iletmelidir. . Aklıma gelen iki alternatif (lütfen sözdizimini görmezden gelin, belirli bir dil değil)

1) anahtar (berbat olduğunu biliyorum)

//inside the view controller
void onClickItem(int index) {
    A a = items.get(index);

    switch(a.type) {
         case b:
             B b = (B)a;
             go to screen X;
             x.v1 = b.v1; // fill X with b data
             x.v2 = b.v2; 
         case c:
             go to screen Y;
         etc...
    }
}

2) Çok Biçimlilik

//inside the view controller
void onClickItem(int index) {
    A a = items.get(index);
    Screen s = new (a.getDestinationScreen()); //ignore the syntax
    s.v1 = a.v1;   // fill s with information about A
    s.v2 = a.v2;
    show(s);
}

//inside B
Class getDestinationScreen(void) {
    return Class(X);
}

//inside C
Class getDestinationScreen(void) {
    return Class(Y);
}

Çözüm 2 ile ilgili sorunum, B, C, D, vb model olduğu için, görünümle ilgili şeyleri bilmemeleri gerektiğidir. Yoksa bu durumda mı olmalılar?

Yanıtlar:


6

Belki de ziyaretçi kalıbının uygulanmasının burada yararlı olacağını düşünüyorum. Görünüm türünü belirlemek için B, C ve D sınıfının "ziyaret edilmesi" gerekir, ancak görünümler hakkında hiçbir şey bilmesine gerek yoktur. ViewFactory (aşağıda) öğeyi ziyaret edecek ve inşa edilecek doğru görünümü belirlemek için polimorfizm kullanacaktır. Anahtar ifadesi yok. Neyin inşa edileceğine karar vermek için model içlerinden sormak yok. Ziyaretçi arayüzü görünüm için doğru ayarlayıcıyı seçmek için polimorfizm kullanır. Ayarlayıcı, öğeyi belirli görünüm türünün (X veya Y veya Z) yapıcısına iletebilir ve bu görünüm alanlarını öğeden doldurabilir.

   //inside the view controller
   void onClickItem(int index) {
      ViewFactoryVisitable a = items.get(index);
      ViewFactory aViewFactory = new ViewFactory(
      s = aViewFactory.getViewFor(a);
      show(s);
   }

--------

//Element interface
public interface ViewFactoryVisitable
{
    public void accept(ViewFactory theViewFactory);
}

---------

public interface ViewFactoryVisitor
{
   // one for each concrete type, polymorphism will choose correct setter
   public set setViewFor(B b);
   public set setViewFor(C c);
   public set setViewFor(D d);
}

--------

// B, C, D must implement this visitable interface
class B implements ViewFactoryVisitable
{ 
   ...

   //accept the ViewFactory as a visitor
   public void accept(ViewFactoryVisitor theViewFactoryVisitor)
   {
      theViewFactoryVisitor. setViewFor(this);
   }

   ...
} 

--------

class ViewFactory implements ViewFactoryVisitor
{
   ViewFactory(ViewFactoryVisitable theItem) {
      theItem.accept(this);
   }

   private View mView = null;
   ...

   public void setViewFor(B b) {
      // construct a view x and populate with data from b
      mView = new ViewX(b); 
   }

   public void setViewFor(C c) {
      mView = new ViewY(c); 
   }

   public void setViewFor(D d) {
      mView = new ViewZ(d); 
   }

   View getView() {
      return mView;
   }

} 

1
Kabulün uygulanması "theViewFactoryVisitor.setViewFor (this);" değilse; Aptal olursam özür dilerim!
Ryan

@Ryan İyi yakalayın. Bu hata 3 yıldır burada!
Chuck Krutsinger

1

Bir cevaptan çok bir yorum daha, ama bence bu bir savurma. Ya Görünüm o ekranı (anahtar) seçebilmesi Modeli hakkında tüm bilmek zorunda ya Modeli böylece Görünümü hakkında tüm bilmek zorunda o ekran (polimorfizm) seçebilir. Bence zaman içinde en basit olacağını düşündüğünüzü seçmek zorundasınız; sorunun doğru cevabı yok . (Umarım birisi beni yanlış kanıtlayabilir.) Ben kendim polimorfizme yöneliyorum.

Bu problemle biraz karşılaşıyorum. En sinir bozucu vaka, örnekleri bir harita üzerinde dolaşan bir Wanderer sınıfıydı. Çizmek için ekranın Wanderer hakkında bilmesi gerekiyordu veya Wanderer'ın ekran hakkında bilmesi gerekiyordu. Sorun iki ekran vardı (daha fazla geliyor). Farklı Wanderer alt sınıflarının sayısı arttıkça ve çizim kodunu Wanderer alt sınıflarına koydum. Bu, her büyük sınıfın Graphics2D hakkında bilmeniz gereken bir yöntem ve Java3D hakkında bilmeniz gereken bir yöntem olduğu anlamına geliyordu . Çirkin.

Sonunda bana iki paralel sınıf yapısı vererek sınıfı böldüm. Wanderer sınıf grafiklerle ilgili bilerek kurtuldu, ama DrawWanderer sınıfı daha da Wanderer hakkında iyi olandan bilmek gerekli ve bu konuda bilmemiz gereken iki (ve belki de daha fazla) tamamen farklı bir grafik ortamlar (Görünümler). (Sanırım bu sınıf bölünmesi fikri bir çeşit cevap olabilir, ama gerçekten yaptığı tek şey sorunu biraz içermek.)

Bunun Nesne Odaklı tasarımın çok genel ve temel bir sorunu olduğunu düşünüyorum.


0

Anahtarla devam etmek, bu durum için polimorfizmden daha iyi bir seçenek olduğunu düşünüyorum.

Yapması oldukça basit bir şey, bu yüzden polimorfizm kullanımı ile aşırı karmaşık olması gerektiğini düşünmüyorum.

Bu blog yazısında madeni para yazmak istiyorum . Anahtar ifadeleri, doğru şekilde kullandığınız sürece çirkin olmak zorunda değildir. Ve sizin durumunuzda, bir kontrol cihazında kullanım için böyle soyutlama modelleri aşırı olabilir ve istenmeyen sonuçlar ortaya çıkarabilir. SRP'yi ihlal etmek gibi.


Senin değinmek istediğin noktayı anlıyorum. Ben polimorfizmin aşırı karmaşık olduğunu düşünmüyorum. Ve benim durumumdaki A sınıfı soyut değil, aslında kullanılıyor. Düşünceleriniz için teşekkür ederim, yine de daha iyi bir çözüm ve polimorfizm yaklaşımına daha meyilli olmayı bekliyorum.
Raphael Oliveira

1
Endişeye gerek yok, sadece 2 sentimi konuya veriyorum. Modelinize görünüm mantığı koymak zorunda kalmanıza rağmen, her zaman bunları dekoratörler ile sarabilirsiniz, böylece modelleriniz görünüm mantığından uzak kalır. Ardından, model yerine dekoratör sınıflarında polimorfizm kullanabilirsiniz.
Maru

0

Çözüm 2 ile ilgili sorunum, B, C, D, vb model olduğu için, görünümle ilgili şeyleri bilmemeleri gerektiğidir.

Bu endişeye katılıyorum. Ayrıca, bir birleşik giriş kutusunda oturan nesnelerin davranışlarının olacağı konusunda biraz endişeliyim. Bunun hiç yapmadığı "kötü bir şey" olduğundan emin değilim, bu benim için doğal olmayan bir seçim gibi görünüyor.

Ayrıca, öyle görünmüyor Ave alt sınıfları, ilginç polimorfizme sahip olduğunuz tiptir. İlginç olan aslında Screen. Bu örnekte, yaratılışı Abilgilendirmek için bilgi tutan bir sınıftır Screen.

Açılan kutunun a.typedöndürdüğünün bir listesini içermesini sağlarsanız, bir switch deyimi daha doğal görünür. Ancak, tıklama olayı işleyicisine doğru koymak yerine, a ScreenFactory. Sonra var:

//inside the view controller
void onClickItem(int index) {
    A a = items.get(index);

    s = _screenFactory.GetScreen(a);
    show(s);
    }
}

//inside a ScreenFactory implementation
internal Screen GetScreen(A typeIndicator)
{
switch(a.type) {
     case b:
         return new ScreenX();
     case c:
         return new ScreenY();
     etc...        
}

Bu, ekran oluşturma davranışını test etmenizi sağlar ve bazı işlevleri kullanıcı arayüzünüzden güzel bir şekilde çıkarır. Görünüm katmanınızı sağlam tutar. Belki de, Aalt sınıflar typeiçerdikleri bayrağa daraltılabilirse , tasarımınızı basitleştirir .


Uzun boylu cevap için teşekkür ederim. Ne yazık ki, modeller sadece türlerini veya hedef görünüm denetleyicisini değil, çok fazla bilgi içerir. Ayrıca, her ne kadar bahsetmedim, ScreenX, ScreenY vb. İnşaat hakkında B, C, D hakkında bilgi almalı, bu yüzden sadece türü geçen bir fabrikayı kullanamıyorum, modelin kendisini geçmem gerekiyor.
Raphael Oliveira
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.