카테고리 없음

[자바] Model-View-Presenter 패시브 뷰 : 부트 스트래핑-누가 처음에 뷰를 표시합니까?

행복을전해요 2021. 1. 27. 02:40

옵션 (3) 끝까지. 보기를 표시하는 것을 포함하여보기를 "제어"하는 것은 발표자의 작업입니다. 예,이를 허용하려면 뷰의 인터페이스에 추가해야하지만 큰 문제는 아닙니다. 가능한 한 수동적 인 뷰를 만들 수 있습니다. 논리가 전혀 없습니다!

작업 예 :

나는 MVC 아키텍처를 사용하는 간단한 스윙 게임

의이 예제

우연히 발견했습니다 . MVC 대신 MVP를 사용하여 스윙 앱을 작성했기 때문에이 예제가 MVC의 진실하고 순수한 예제인지 권위있게 말할 수 없습니다. 그것은 나에게 괜찮아 보이며, 저자

trashgod

는 Swing을 사용하여 여기에서 자신을 입증 한 것 이상으로 합리적이라고 받아 들일 것입니다.연습으로 MVP 아키텍처를 사용하여 다시 작성하기로 결정했습니다.


드라이버 :

아래 코드에서 볼 수 있듯이 이것은 매우 간단합니다. 당신에게 튀어 나와야 할 것은 (생성자를 검사하여) 관심사 분리입니다.

  • 모델

    클래스는 독립형이며, 뷰 또는 발표자의 지식이 없습니다.
  • 보기

    인터페이스는 독립형 GUI 클래스에 의해 구현하지, 어느 쪽도 어느 모델이나 발표자의 지식을 가지고있다.
  • 발표자

    클래스는 모델과 뷰 모두에 대해 알고있다.

암호:

import java.awt.*;

/**
 * MVP version of https://stackoverflow.com/q/3066590/230513
  */
  public class MVPGame implements Runnable
  {
    public static void main(String[] args)
      {
          EventQueue.invokeLater(new MVPGame());
            }
            
              @Override
                public void run()
                  {
                      Model model = new Model();
                          View view = new Gui();
                              Presenter presenter = new Presenter(model, view);
                                  presenter.start();
                                    }
                                    }
                                    

그리고 게임에 사용할 GamePiece :

import java.awt.*;

public enum GamePiece
{
  Red(Color.red), Green(Color.green), Blue(Color.blue);
    public Color color;
    
      private GamePiece(Color color)
        {
            this.color = color;
              }
              }
              

모델 :

주로 모델 의 역할은 다음과 같습니다.

  • UI에 대한 데이터 제공 (요청시)
  • 데이터 유효성 검사 (요청시)
  • 데이터 장기 저장 (요청시)

암호:

import java.util.*;

public class Model
{
  private static final Random rnd = new Random();
    private static final GamePiece[] pieces = GamePiece.values();
    
      private GamePiece selection;
      
        public Model()
          {
              reset();
                }
                
                  public void reset()
                    {
                        selection = pieces[randomInt(0, pieces.length)];
                          }
                          
                            public boolean check(GamePiece guess)
                              {
                                  return selection.equals(guess);
                                    }
                                    
                                      public List<GamePiece> getAllPieces()
                                        {
                                            return Arrays.asList(GamePiece.values());
                                              }
                                              
                                                private static int randomInt(int min, int max)
                                                  {
                                                      return rnd.nextInt((max - min) + 1) + min;
                                                        }
                                                        }
                                                        

보기 :

여기서 아이디어는 가능한 한 많은 애플리케이션 로직을 제거하여 가능한 한 "멍청한"것으로 만드는 것입니다 (목표는 아무것도 갖지 않는 것입니다). 장점 :

  • JUnit스윙 코드와 혼합 된 애플리케이션 로직이 없으므로 이제 앱을 100 % 테스트 할 수 있습니다.
  • 전체 앱을 실행하지 않고도 GUI를 실행할 수 있으므로 프로토 타이핑이 훨씬 빨라집니다.

암호:

import java.awt.*;
import java.awt.event.*;
import java.util.List;

public interface View
{
  public void addPieceActionListener(GamePiece piece, ActionListener listener);
    public void addResetActionListener(ActionListener listener);
      public void setGamePieces(List<GamePiece> pieces);
        public void setResult(Color color, String message);
        }
        

및 GUI :

import java.awt.*;
import java.awt.event.*;
import java.util.List;
import javax.swing.*;

/**
 * View is "dumb". It has no reference to Model or Presenter.
  * No application code - Swing code only!
   */
   public class Gui implements View
   {
     private JFrame frame;
       private ColorIcon icon;
         private JLabel resultLabel;
           private JButton resetButton;
             private JButton[] pieceButtons;
               private List<GamePiece> pieceChoices;
               
                 public Gui()
                   {
                       frame = new JFrame();
                           frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                               icon = new ColorIcon(80, Color.WHITE);
                                 }
                                 
                                   public void setGamePieces(List<GamePiece> pieces)
                                     {
                                         this.pieceChoices = pieces;
                                         
                                             frame.add(getMainPanel());
                                                 frame.pack();
                                                     frame.setLocationRelativeTo(null);
                                                         frame.setVisible(true);
                                                           }
                                                           
                                                             public void setResult(Color color, String message)
                                                               {
                                                                   icon.color = color;
                                                                       resultLabel.setText(message);
                                                                           resultLabel.repaint();
                                                                             }
                                                                             
                                                                               private JPanel getMainPanel()
                                                                                 {
                                                                                     JPanel panel = new JPanel(new BorderLayout());
                                                                                         panel.add(getInstructionPanel(), BorderLayout.NORTH);
                                                                                             panel.add(getGamePanel(), BorderLayout.CENTER);
                                                                                                 panel.add(getResetPanel(), BorderLayout.SOUTH);
                                                                                                     return panel;
                                                                                                       }
                                                                                                       
                                                                                                         private JPanel getInstructionPanel()
                                                                                                           {
                                                                                                               JPanel panel = new JPanel();
                                                                                                                   panel.add(new JLabel("Guess what color!", JLabel.CENTER));
                                                                                                                       return panel;
                                                                                                                         }
                                                                                                                         
                                                                                                                           private JPanel getGamePanel()
                                                                                                                             {
                                                                                                                                 resultLabel = new JLabel("No selection made", icon, JLabel.CENTER);
                                                                                                                                     resultLabel.setVerticalTextPosition(JLabel.BOTTOM);
                                                                                                                                         resultLabel.setHorizontalTextPosition(JLabel.CENTER);
                                                                                                                                         
                                                                                                                                             JPanel piecePanel = new JPanel();
                                                                                                                                                 int pieceCount = pieceChoices.size();
                                                                                                                                                     pieceButtons = new JButton[pieceCount];
                                                                                                                                                     
                                                                                                                                                         for (int i = 0; i < pieceCount; i++)
                                                                                                                                                             {
                                                                                                                                                                   pieceButtons[i] = createPiece(pieceChoices.get(i));
                                                                                                                                                                         piecePanel.add(pieceButtons[i]);
                                                                                                                                                                             }
                                                                                                                                                                             
                                                                                                                                                                                 JPanel panel = new JPanel(new BorderLayout());
                                                                                                                                                                                     panel.add(resultLabel, BorderLayout.CENTER);
                                                                                                                                                                                         panel.add(piecePanel, BorderLayout.SOUTH);
                                                                                                                                                                                         
                                                                                                                                                                                             return panel;
                                                                                                                                                                                               }
                                                                                                                                                                                               
                                                                                                                                                                                                 private JPanel getResetPanel()
                                                                                                                                                                                                   {
                                                                                                                                                                                                       resetButton = new JButton("Reset");
                                                                                                                                                                                                       
                                                                                                                                                                                                           JPanel panel = new JPanel();
                                                                                                                                                                                                               panel.add(resetButton);
                                                                                                                                                                                                                   return panel;
                                                                                                                                                                                                                     }
                                                                                                                                                                                                                     
                                                                                                                                                                                                                       private JButton createPiece(GamePiece piece)
                                                                                                                                                                                                                         {
                                                                                                                                                                                                                             JButton btn = new JButton();
                                                                                                                                                                                                                                 btn.setIcon(new ColorIcon(16, piece.color));
                                                                                                                                                                                                                                     btn.setActionCommand(piece.name());
                                                                                                                                                                                                                                         return btn;
                                                                                                                                                                                                                                           }
                                                                                                                                                                                                                                           
                                                                                                                                                                                                                                             public void addPieceActionListener(GamePiece piece, ActionListener listener)
                                                                                                                                                                                                                                               {
                                                                                                                                                                                                                                                   for (JButton button : pieceButtons)
                                                                                                                                                                                                                                                       {
                                                                                                                                                                                                                                                             if (button.getActionCommand().equals(piece.name()))
                                                                                                                                                                                                                                                                   {
                                                                                                                                                                                                                                                                           button.addActionListener(listener);
                                                                                                                                                                                                                                                                                   break;
                                                                                                                                                                                                                                                                                         }
                                                                                                                                                                                                                                                                                             }
                                                                                                                                                                                                                                                                                               }
                                                                                                                                                                                                                                                                                               
                                                                                                                                                                                                                                                                                                 public void addResetActionListener(ActionListener listener)
                                                                                                                                                                                                                                                                                                   {
                                                                                                                                                                                                                                                                                                       resetButton.addActionListener(listener);
                                                                                                                                                                                                                                                                                                         }
                                                                                                                                                                                                                                                                                                         
                                                                                                                                                                                                                                                                                                           private class ColorIcon implements Icon
                                                                                                                                                                                                                                                                                                             {
                                                                                                                                                                                                                                                                                                                 private int size;
                                                                                                                                                                                                                                                                                                                     private Color color;
                                                                                                                                                                                                                                                                                                                     
                                                                                                                                                                                                                                                                                                                         public ColorIcon(int size, Color color)
                                                                                                                                                                                                                                                                                                                             {
                                                                                                                                                                                                                                                                                                                                   this.size = size;
                                                                                                                                                                                                                                                                                                                                         this.color = color;
                                                                                                                                                                                                                                                                                                                                             }
                                                                                                                                                                                                                                                                                                                                             
                                                                                                                                                                                                                                                                                                                                                 @Override
                                                                                                                                                                                                                                                                                                                                                     public void paintIcon(Component c, Graphics g, int x, int y)
                                                                                                                                                                                                                                                                                                                                                         {
                                                                                                                                                                                                                                                                                                                                                               Graphics2D g2d = (Graphics2D) g;
                                                                                                                                                                                                                                                                                                                                                                     g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                                                                                                                                                                                                                                                                                                                                                                               RenderingHints.VALUE_ANTIALIAS_ON);
                                                                                                                                                                                                                                                                                                                                                                                     g2d.setColor(color);
                                                                                                                                                                                                                                                                                                                                                                                           g2d.fillOval(x, y, size, size);
                                                                                                                                                                                                                                                                                                                                                                                               }
                                                                                                                                                                                                                                                                                                                                                                                               
                                                                                                                                                                                                                                                                                                                                                                                                   @Override
                                                                                                                                                                                                                                                                                                                                                                                                       public int getIconWidth()
                                                                                                                                                                                                                                                                                                                                                                                                           {
                                                                                                                                                                                                                                                                                                                                                                                                                 return size;
                                                                                                                                                                                                                                                                                                                                                                                                                     }
                                                                                                                                                                                                                                                                                                                                                                                                                     
                                                                                                                                                                                                                                                                                                                                                                                                                         @Override
                                                                                                                                                                                                                                                                                                                                                                                                                             public int getIconHeight()
                                                                                                                                                                                                                                                                                                                                                                                                                                 {
                                                                                                                                                                                                                                                                                                                                                                                                                                       return size;
                                                                                                                                                                                                                                                                                                                                                                                                                                           }
                                                                                                                                                                                                                                                                                                                                                                                                                                             }
                                                                                                                                                                                                                                                                                                                                                                                                                                             }
                                                                                                                                                                                                                                                                                                                                                                                                                                             

당장 명확하지 않은 것은 View 인터페이스가 얼마나 커질 수 있는지입니다. GUI의 각 Swing 구성 요소에 대해 다음을 수행 할 수 있습니다.

  • 많은 유형 (ActionListener, FocusListener, MouseListener 등)이있는 구성 요소에 리스너를 추가 / 제거합니다.
  • 구성 요소의 데이터 가져 오기 / 설정
  • 구성 요소의 "사용성"상태 (활성화, 표시, 편집 가능, 초점 가능 등)를 설정합니다.

이것은 정말 빨리 다루기 어려울 수 있습니다. 해결책으로 (이 예에는 표시되지 않음) 각 필드에 대해 키가 생성되고 GUI가 해당 키로 각 ​​구성 요소를 등록합니다 (HashMap 사용). 그런 다음 View 대신 다음과 같은 메서드를 정의합니다.

public void addResetActionListener(ActionListener listener);
// and then repeat for every field that needs an ActionListener

단일 방법이 있습니다.

public void addActionListener(SomeEnum someField, ActionListener listener);

여기서 "SomeEnum"은

enum

주어진 UI의 모든 필드를 정의 하는 입니다. 그런 다음 GUI가 해당 호출을 수신하면 해당 메서드를 호출 할 적절한 구성 요소를 찾습니다. 이 모든 무거운 작업은 View를 구현하는 추상 수퍼 클래스에서 수행됩니다.


발표자 :

책임은 다음과 같습니다.

  • 시작 값으로보기 초기화
  • 적절한 리스너를 연결하여 View의 모든 사용자 상호 작용에 응답합니다.
  • 필요할 때마다보기 상태 업데이트
  • 뷰에서 모든 데이터를 가져와 저장을 위해 모델로 전달 (필요한 경우)

코드 (여기에는 스윙이 없습니다) :

import java.awt.*;
import java.awt.event.*;

public class Presenter
{
  private Model model;
    private View view;
    
      public Presenter()
        {
            System.out.println("ctor");
              }
              
                public Presenter(Model model, View view)
                  {
                      this.model = model;
                          this.view = view;
                            }
                            
                              public void start()
                                {
                                    view.setGamePieces(model.getAllPieces());
                                        reset();
                                        
                                            view.addResetActionListener(new ActionListener()
                                                {
                                                      public void actionPerformed(ActionEvent e)
                                                            {
                                                                    reset();
                                                                          }
                                                                              });
                                                                              
                                                                                  for (int i = 0; i < GamePiece.values().length; i++)
                                                                                      {
                                                                                            final GamePiece aPiece = GamePiece.values()[i];
                                                                                                  view.addPieceActionListener(aPiece, new ActionListener()
                                                                                                        {
                                                                                                                public void actionPerformed(ActionEvent e)
                                                                                                                        {
                                                                                                                                  pieceSelected(aPiece);
                                                                                                                                          }
                                                                                                                                                });
                                                                                                                                                    }
                                                                                                                                                      }
                                                                                                                                                      
                                                                                                                                                        private void reset()
                                                                                                                                                          {
                                                                                                                                                              model.reset();
                                                                                                                                                                  view.setResult(Color.GRAY, "Click a button.");
                                                                                                                                                                    }
                                                                                                                                                                    
                                                                                                                                                                      private void pieceSelected(GamePiece piece)
                                                                                                                                                                        {
                                                                                                                                                                            boolean valid = model.check(piece);
                                                                                                                                                                                view.setResult(piece.color, valid ? "Win!" : "Keep trying.");
                                                                                                                                                                                  }
                                                                                                                                                                                  }
                                                                                                                                                                                  

MVP 아키텍처의 각 부분은 많은 작업을 수행하기 위해 다른 클래스 (다른 2 개 부분에 숨겨져 있음)에 위임 될 수 있습니다. Model, View 및 Presenter 클래스는 코드 기반 계층의 상위 부분에 불과합니다.

출처
https://stackoverflow.com/questions/22029808