ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 객체지향과 디자인패턴 1
    언어/객체지향 2023. 8. 11. 11:05

    1. 지저분한 코드 

     

    최초 요구사항: 메뉴영역에 메뉴1과 메뉴2가 있다. 공통영역에 버튼 1이 있다.

                           - 메뉴를 누르면 각 메뉴로 화면전환

                           -버튼을 누르면 각 메뉴에 맞는 화면처리를 한다.

     

    public class Application implements OnClickedListener {
        private Menu menu1 = new Menu("menu1");
        private Menu menu2 = new Menu("menu2");
        private Button button1 = new Button("bu1");
        private String currentMenu = null;
    
        public Application(){
            menu1.setOnClickListener(this); // 클릭시 이벤트 담당하는 클래스 등록
            menu2.setOnClickListener(this);
            button1.setOnClickListener(this);
    
        }
    
        public void clicked(Component eventSource){
            if(eventSource.getId().equals("menu1"))
                changeUIToMenu1();
            else if (eventSource.getId().equals("menu2"))
                changeUIToMenu2();
            else if (eventSource.getId().equals("button1"))
               if(currentMenu == null)
                   return;
               if(currentMenu.equals("menu1"))
                   precessButton1WhenMenu1();
               else if (currentMenu.equals("menu2")) {
                   processButton1WhenMenu2();
                   
               }
        }
    
        private void processButton1WhenMenu2() {
        //..
        }
    
        private void precessButton1WhenMenu1() {
        //..
        }
    
        private void changeUIToMenu2() {
        //..
        }
    
        private void changeUIToMenu1() {
        //..
        }
    }

    - 두 개의 메뉴와 한 개의 버튼에서 이벤트가 발생하면, 그 이벤트를 clicked()메서드에서 처리한다. (각 버튼에 OnClickedListener 클래스(clicked 메서드 가짐) 등록 

    - 위 클래스는 하나의 클래스가 메뉴1,2,버튼1도 포함하면서, 화면처리 이벤트도 처리한다.

    - 이런경우 만약 메뉴3과 버튼2가 포함된다고 가정해보자. -> 메뉴와 버튼 클릭처리를 위해 if-else구조가 중첩될 것이다.

    - 하나의 클래스에서 여러 버튼의 책임을 혼자서 책임지려다보니 코드가 복잡해진다.

     

    2. 수정하기 좋은 코드로 변경 

     

    - 이 상황을 객체 지향 방식으로 

    - 요구사항을 다시 생각해보면, 메뉴가 선택되면 해당 화면을 보여준다. 버튼이 클랙되면 선택된 메뉴에 맞는 처리를 한다.

    - 위 두개의 공통 동작을 인터페이스화 해보자 

     

    - 인터페이스 

    public interface ScreenUI {
        public void show();
        public void handleButton1Click();
    }

    - 구현체

    public class Menu1UI implements ScreenUI {
        @Override
        public void show() {
    		//..
        }
    
        @Override
        public void handleButton1Click() {
    		//..
        }
    }
    public class Application implements OnClickedListener {
        private Menu menu1 = new Menu("menu1");
        private Menu menu2 = new Menu("menu2");
        private Button button1 = new Button("bu1");
    
        private ScreenUI currentMenu=null;
        public Application(){
            menu1.setOnClickListener(this);
            menu2.setOnClickListener(this);
            button1.setOnClickListener(this);
    
        }
    
        public void clicked(Component eventSource){
            String ev = eventSource.getId();
            if(ev.equals("menu1")) {
                currentMenu = new Menu1UI();
                currentMenu.show();
            } else if (ev.equals("menu2")) {
                currentMenu = new Menu2UI();
                currentMenu.show();
            } else if (ev.equals("button1")) {
                if(currentMenu==null)return;
                currentMenu.handleButton1Click();
    
            }
        }

    - 버튼1을 클릭을 처리하는 코드는 현재 화면이 메뉴1인지 2인지 상관없이, currentMenu에 handleButtonClick()를 호출한다. 

    - 위와 같이 수정할 수 있다. 각 메뉴화면과 버튼 클릭시 처리에 대한 책임을 메뉴가 가지도록 변경했다.

    - 메뉴3이나, 버튼이 추가되면, 이전과 다르게 ScreenUI를 구현한 메뉴3을 추가 혹은 button2를 처리하는 메서드를 ScreenUI에 추가해서 각 클래스별로 구현하도록 하면 된다.

     

    3. clicked메서드에서 버튼을 처리하는 것과 메뉴 처리하는 것 분리 

     

    private ScreenUI currentMenu=null;
        public Application(){
            menu1.setOnClickListener(menuListener);
            menu2.setOnClickListener(menuListener);
            button1.setOnClickListener(buttonListener);
    
        }
    
        private OnClickedListener menuListener = new OnClickedListener() {
            @Override
            public void clicked(Component eventSource) {
                String ev = eventSource.getId();
                if (ev.equals("menu1")) {
                    currentMenu = new Menu1UI();
                } else if (ev.equals("menu2")) {
                    currentMenu = new Menu2UI();
    
                    currentMenu.show();
                }
            }
        };
    
    
            private OnClickedListener buttonListener = new OnClickedListener() {
                @Override
                public void clicked(Component eventSource) {
                    if (currentMenu == null) return;
                    String ev = eventSource.getId();
                    if (ev.equals("button1"))
                        currentMenu.handleButton1Click();
                }
            };

    - 메뉴와 버튼이 다른 OnClickedListener를 등록하도록 하여, 클릭시 서로 다른 clicked()가 호출됨 

    - 각 메뉴와 버튼은 메뉴와 버튼이 추가, 삭제 될 때 마다 바뀔텐데 기존처럼 하나의 메서드에서 이를 다 처리하면, 가독성이 떨어진다.

     

     

    - 객체지향코드로 바뀌면서 클래스가 추가되었지만, 기존보다 유지보수가 쉬워졌다.

        > 새로운 메뉴 추가시 버튼 처리 코드가 영향 받지 않는다.(clicked())

        >  한 메뉴 관련 코드가 하나의 클래스로 모여서 코드 분석 수정이 용이하다.

        > 서로 다른 메뉴에 대한 처리 코드가 섞여 있지 않아 수정이 용이하다.

    - 각 객체의 책임을 분리하여 다른 클래스로 작성하였기 때문에, 특정 객체를 수정해야할 때 불필요하게 다른 객체의 코드를 볼 필요가 없어졌다.

     

Designed by Tistory.