언어/객체지향

객체지향과 디자인패턴 1

now0204 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())

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

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

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