Chuyển đổi so với đa hình khi làm việc với mô hình và chế độ xem


12

Tôi không thể tìm ra một giải pháp tốt hơn cho vấn đề của mình. Tôi có một bộ điều khiển xem trình bày một danh sách các yếu tố. Các phần tử đó là các mô hình có thể là một thể hiện của B, C, D, v.v. và kế thừa từ A. Vì vậy, trong trình điều khiển khung nhìn đó, mỗi mục sẽ chuyển đến một màn hình khác nhau của ứng dụng và chuyển một số dữ liệu khi người dùng chọn một trong số chúng . Hai lựa chọn thay thế xuất hiện trong đầu tôi là (xin vui lòng bỏ qua cú pháp, nó không phải là một ngôn ngữ cụ thể)

1) chuyển đổi (tôi biết rằng hút)

//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) đa hình

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

Vấn đề của tôi với giải pháp 2 là vì B, C, D, v.v. là các mô hình, nên họ không nên biết về các nội dung liên quan đến chế độ xem. Hay họ nên trong trường hợp đó?

Câu trả lời:


6

Tôi nghĩ rằng có lẽ việc triển khai mô hình khách truy cập sẽ hữu ích ở đây. Lớp B, C và D sẽ cần được "truy cập" để xác định loại chế độ xem, nhưng sẽ không cần biết gì về chế độ xem. ViewFactory (bên dưới) sẽ truy cập vào mục và sử dụng đa hình để xác định chế độ xem chính xác để xây dựng. Không có báo cáo chuyển đổi. Không hỏi về mô hình nội bộ để quyết định xây dựng cái gì. Giao diện khách truy cập sử dụng đa hình để chọn bộ cài đặt chính xác cho chế độ xem. Trình thiết lập có thể chuyển mục cho hàm tạo của kiểu xem cụ thể (X hoặc Y hoặc Z) và chế độ xem đó có thể điền các trường của nó từ mục đó.

   //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
Nếu việc triển khai chấp nhận không phải là "theViewFactoryVisitor.setViewFor (this);" Xin lỗi nếu tôi ngu ngốc!
Ryan

@Ryan Bắt tốt. Sai lầm này đã ở đây 3 năm!
Chuck Krutsinger

1

Nhiều hơn một nhận xét hơn là một câu trả lời, nhưng tôi nghĩ rằng đó là một tung lên. Hoặc là View có biết tất cả về mô hình để nó có thể chọn màn hình (chuyển đổi) hoặc Model phải biết tất cả về Xem để có thể chọn màn hình (polymorphism). Tôi nghĩ bạn phải chọn những gì bạn nghĩ sẽ đơn giản nhất theo thời gian; không có quyền câu trả lời cho câu hỏi (Tôi hy vọng ai đó có thể chứng minh tôi sai.) Tôi tự nghiêng về đa hình.

Tôi va vào vấn đề này một chút. Trường hợp khó chịu nhất là một lớp giang hồ, những trường hợp đi lang thang trên bản đồ. Để vẽ nó, màn hình cần biết về Wanderer hoặc Wanderer cần biết về màn hình. Vấn đề là có hai màn hình (sẽ xuất hiện nhiều hơn). Vì số lượng các lớp con giang hồ khác nhau rất lớn và ngày càng tăng, tôi đặt mã vẽ trong các lớp con của Wanderer. Điều đó có nghĩa là mỗi lớp lớn có chính xác một phương thức cần biết về Graphics2D chính xác một phương thức cần biết về Java3D. Xấu xí.

Cuối cùng tôi đã tách lớp, cho tôi hai cấu trúc lớp song song. Lớp Wanderer được giải phóng khỏi việc biết về đồ họa, nhưng lớp DrawWanderer vẫn cần biết nhiều hơn về Wanderer hơn là đàng hoàng cần biết về hai (và có thể nhiều hơn) môi trường đồ họa hoàn toàn khác nhau (Lượt xem). (Tôi cho rằng ý tưởng chia lớp này có thể là một câu trả lời của các loại, nhưng tất cả những gì nó thực sự chỉ chứa đựng vấn đề một chút.)

Tôi nghĩ rằng đây là một vấn đề rất chung và cơ bản của thiết kế hướng đối tượng.


0

Tôi nghĩ rằng đi với chuyển đổi là một lựa chọn tốt hơn so với đi với đa hình cho trường hợp này.

Đó là một điều khá đơn giản để làm, vì vậy tôi không nghĩ rằng nó phải được áp dụng quá mức bằng cách sử dụng đa hình.

Tôi muốn xu trong bài viết trên blog này . Chuyển đổi câu lệnh không nhất thiết là xấu xí miễn là bạn sử dụng chúng đúng cách. Và trong trường hợp của bạn, các mô hình Trừu tượng như thế để sử dụng trong bộ điều khiển có thể là quá mức cần thiết và có thể mang lại kết quả không mong muốn. Giống như vi phạm SRP.


Tôi thấy điểm của bạn. Chà, tôi không nghĩ rằng đa hình là quá phức tạp. Và lớp A trong trường hợp của tôi không trừu tượng, thực tế nó được sử dụng. Cảm ơn bạn đã suy nghĩ của bạn, mặc dù tôi vẫn đang chờ đợi một giải pháp tốt hơn và nghiêng về phương pháp đa hình.
Raphael Oliveira

1
không phải lo lắng, chỉ đưa ra 2 xu của tôi về vấn đề này. Mặc dù để giải quyết vấn đề của bạn bằng cách đưa logic xem vào các mô hình của bạn, bạn luôn có thể bọc chúng bằng các bộ trang trí để các mô hình của bạn không có logic xem. Sau đó, bạn có thể sử dụng đa hình trên các lớp trang trí thay vì mô hình.
Maru

0

Vấn đề của tôi với giải pháp 2 là vì B, C, D, v.v. là các mô hình, nên họ không nên biết về các nội dung liên quan đến chế độ xem.

Tôi đồng ý với mối quan tâm này. Tôi cũng có một chút lo ngại rằng các đối tượng ngồi trong combobox sẽ có hành vi. Tôi không chắc đó là một "điều tồi tệ" chưa bao giờ làm điều đó, nó dường như là một lựa chọn không tự nhiên đối với tôi.

Ngoài ra, nó có vẻ không giống Avà các lớp con của nó là loại mà bạn có tính đa hình thú vị. Các loại thú vị là thực sự Screen. Trong ví dụ này, Achỉ là một lớp chứa thông tin để thông báo cho Screenviệc tạo.

Nếu bạn tạo combobox chứa danh sách bất kỳ a.typetrả về nào thì câu lệnh switch có vẻ tự nhiên hơn. Tuy nhiên, thay vì đặt nó ngay trong trình xử lý sự kiện nhấp chuột, tôi sẽ đặt nó vào phần a ScreenFactory. Sau đó bạn có:

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

Điều này cho phép bạn kiểm tra hành vi xây dựng màn hình và rút một số chức năng ra khỏi giao diện người dùng của bạn. Nó giữ cho lớp View của bạn nguyên vẹn. Có lẽ nó đơn giản hóa thiết kế của bạn, nếu nó có nghĩa Avà các lớp con có thể được thu gọn vào typecờ mà chúng chứa.


Cảm ơn bạn đã phản hồi Tallseth. Thật không may, các mô hình chứa rất nhiều thông tin, không chỉ loại của chúng hoặc bộ điều khiển xem đích. Ngoài ra, mặc dù tôi không đề cập đến, ScreenX, ScreenY, v.v. cần nhận thông tin về B, C, D khi xây dựng, vì vậy tôi không thể sử dụng một nhà máy chỉ chuyển loại, tôi cần phải tự vượt qua mô hình.
Raphael Oliveira
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.