Beralih vs Polimorfisme saat berhadapan dengan model dan tampilan

12

Saya tidak dapat menemukan solusi yang lebih baik untuk masalah saya. Saya memiliki pengontrol tampilan yang menyajikan daftar elemen. Elemen-elemen itu adalah model yang bisa menjadi instance dari B, C, D, dll dan mewarisi dari A. Jadi dalam view controller itu, setiap item harus menuju ke layar aplikasi yang berbeda dan meneruskan beberapa data ketika pengguna memilih salah satunya . Dua alternatif yang muncul di pikiran saya adalah (tolong abaikan sintaksnya, itu bukan bahasa tertentu)

1) beralih (saya tahu itu menyebalkan)

//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) polimorfisme

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

Masalah saya dengan solusi 2 adalah karena B, C, D, dll adalah model, mereka seharusnya tidak tahu tentang hal-hal terkait tampilan. Atau haruskah mereka dalam kasus itu?

Raphael Oliveira
sumber

Jawaban:

6

Saya pikir mungkin penerapan pola pengunjung akan berguna di sini. Kelas B, C, dan D perlu "dikunjungi" untuk menentukan jenis tampilan, tetapi tidak perlu tahu apa-apa tentang tampilan. ViewFactory (di bawah) akan mengunjungi item dan menggunakan polimorfisme untuk menentukan tampilan yang benar untuk dibuat. Tidak ada pernyataan peralihan. Tidak bertanya tentang model internal untuk memutuskan apa yang akan dibangun. Antarmuka pengunjung menggunakan polimorfisme untuk memilih penyetel yang benar untuk tampilan. Setter dapat meneruskan item ke konstruktor dari tipe tampilan spesifik (X atau Y atau Z) dan tampilan itu kemudian dapat mengisi bidangnya dari item.

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

} 
Chuck Krutsinger
sumber
1
Jika implementasi accept tidak boleh "theViewFactoryVisitor.setViewFor (this);" Maaf jika saya bodoh!
Ryan
@Ryan Tangkapan bagus. Kesalahan ini telah ada di sini selama 3 tahun!
Chuck Krutsinger
1

Lebih banyak komentar daripada jawaban, tetapi saya pikir itu adalah melemparkan. Entah Lihat harus tahu semua tentang Model sehingga dapat memilih layar (switch) atau Model harus tahu semua tentang View sehingga itu dapat memilih layar (polimorfisme). Saya pikir Anda harus memilih apa yang menurut Anda paling sederhana dari waktu ke waktu; tidak ada jawaban yang tepat untuk pertanyaan itu. (Saya harap seseorang dapat membuktikan saya salah.) Saya sendiri condong ke arah polimorfisme.

Saya sedikit membahas masalah ini. Kasing yang paling menyebalkan adalah kelas Wanderer, contoh-contoh yang berkeliaran tentang peta. Untuk menggambarnya, tampilan perlu tahu tentang Wanderer atau Wanderer perlu tahu tentang tampilan. Masalahnya adalah ada dua tampilan (dengan lebih banyak datang). Karena jumlah subclass Wanderer yang berbeda besar dan terus bertambah, saya memasukkan kode gambar dalam subclass Wanderer. Itu berarti setiap kelas besar memiliki tepat satu metode yang perlu diketahui tentang Graphics2D dan tepat satu metode yang perlu diketahui tentang Java3D. Jelek.

Saya akhirnya memisahkan kelas, memberi saya dua struktur kelas paralel. Kelas Wanderer dibebaskan dari pengetahuan tentang grafis, tetapi kelas DrawWanderer masih perlu tahu lebih banyak tentang Wanderer daripada yang layak dan perlu tahu tentang dua (dan mungkin lebih) lingkungan grafis yang sangat berbeda (Views). (Saya kira ide pemisahan-kelas ini mungkin merupakan jawaban, tetapi yang benar-benar dilakukannya adalah sedikit mengandung masalah.)

Saya pikir ini adalah masalah yang sangat umum dan mendasar dari desain Berorientasi Objek.

RalphChapin
sumber
0

Saya pikir menggunakan saklar adalah pilihan yang lebih baik daripada menggunakan polimorfisme untuk kasus ini.

Ini hal yang cukup sederhana untuk dilakukan, jadi saya tidak berpikir itu harus terlalu rumit dengan menggunakan polimorfisme.

Saya ingin koin di posting blog ini . Ganti pernyataan tidak selalu jelek asalkan Anda menggunakannya dengan benar. Dan dalam kasus Anda, model abstrak seperti itu untuk digunakan dalam controller mungkin berlebihan dan mungkin menghasilkan hasil yang tidak diinginkan. Seperti melanggar SRP.

Maru
sumber
Saya mengerti maksud Anda. Yah, saya tidak berpikir polimorfisme terlalu rumit. Dan kelas A dalam kasus saya tidak abstrak, itu sebenarnya digunakan. Terima kasih atas pemikiran Anda, meskipun saya masih menunggu solusi yang lebih baik dan lebih cenderung pada pendekatan polimorfisme.
Raphael Oliveira
1
jangan khawatir, hanya memberi saya 2 sen untuk masalah ini. Meskipun untuk menyelesaikan masalah Anda dengan harus memasukkan logika tampilan ke dalam model Anda, Anda selalu dapat membungkusnya dengan dekorator sehingga model Anda tetap bebas dari logika tampilan. Kemudian Anda dapat menggunakan polimorfisme pada kelas dekorator, bukan model.
Maru
0

Masalah saya dengan solusi 2 adalah karena B, C, D, dll adalah model, mereka seharusnya tidak tahu tentang hal-hal terkait tampilan.

Saya setuju dengan masalah ini. Saya juga sedikit khawatir bahwa benda yang duduk dalam kotak kombo akan memiliki perilaku. Saya tidak yakin itu "hal buruk" karena tidak pernah melakukannya, sepertinya pilihan yang tidak wajar bagi saya.

Juga, sepertinya tidak Adan subclassnya adalah tipe yang Anda miliki dengan polimorfisme yang menarik. Tipe yang menarik sebenarnya Screen. Dalam contoh ini, Ahanya kelas yang menyimpan informasi untuk menginformasikan Screenpembuatan.

Jika Anda membuat kotak kombo berisi daftar apa pun yang a.typedikembalikan maka pernyataan beralih tampak lebih alami. Namun, alih-alih meletakkannya di event handler klik, saya akan memasukkannya ke dalam ScreenFactory. Maka Anda memiliki:

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

Ini memungkinkan Anda menguji perilaku pembuatan layar, dan menarik beberapa fungsionalitas dari UI Anda. Itu membuat tampilan layering Anda utuh. Mungkin itu menyederhanakan desain Anda, jika itu berarti Adan subkelas dapat diciutkan menjadi typebendera yang dikandungnya.

tallseth
sumber
Terima kasih atas tanggapannya. Sayangnya, model berisi banyak informasi, bukan hanya tipe atau pengontrol tampilan tujuan. Juga, meskipun saya tidak menyebutkan, ScreenX, ScreenY dll perlu menerima informasi tentang B, C, D pada konstruksi, jadi saya tidak dapat menggunakan pabrik hanya melewati jenis, saya harus melewati model itu sendiri.
Raphael Oliveira