https://link.coupang.com/a/QoNwV
본문의 내용은 위 책에서 정리한 내용 일부이며, 자세히 알고 싶은 분들은 위 책을 구매해서 보시는 것을 추천드립니다.
씹고 뜯고 맛보고 즐겨도 내용이 지루하지 않고, 정말 돈이 아깝지 않은 책!
소프트웨어의 가치
소프트웨어의 가치는 사용자가 요구하는 기능을 올바르게 제공하는 데 있음.
변화에 잘 대응할 수 있도록 소프트웨어의 구조를 만들고 더 빠른 시간에 더 적은 노력을 들여서 수정할 수 있는 방향이 바람직
변화 가능한 유연한 구조를 만들어 주는 핵심 기법 중 하나가 객체 지향임.
객체 지향에서는 추상화와 다형성을 이용해 변화되는 부분을 관리한다.
- 추상화란 무엇일까? sw개발에서 변화될 수 있는 로직, 개념 부분을 일반적인 공통점,명칭으로 추출하는 것. 인터페이스?
- 다형성이란 뭘까? 여러 인스턴스를 하나의 멤버변수로 받을 수 있게 해주어서 sw 로직 변화에서 닫히게 해주는 것?
--> 이 모든게 조립을 통한 재사용(구현) 을 기존 코드 변경 없이 구현하기 위해, 필요한 경우에 다른 인터페이스의 구현체를 넣을 수 있도록 위함인 것 같음
최초 상황은 메뉴1, 메뉴2, 버튼 1이 존재하는 상태.
앞의 예제에서 메뉴1, 메뉴2를 선택했을 때 비슷하게 동작하는 것들이 있고, 아래와 같음
1. 메뉴가 선택되면 해당 화면을 보여준다.
2, 버튼1을 클릭하면 선택된 메뉴 화면에서 알맞은 처리를 해준다.
- 변화되는 부분은 1.메뉴를 선택하면 화면이 바뀐다. 1.메뉴가 선택된 상태에서 2. 버튼이 눌리면 처리를 해준다. 버튼은 어떤 메뉴인지에 따라 의존적이고, 화면의 변화는 어떤 메뉴를 선택했는지에 따라 이 경우는 의존적이다.
결국 변화의 포인트는 메뉴, 버튼 총 2개이고 버튼은 메뉴에 선택 상태에 따라 의존하므로 저 2가지 변화를 메서드로 추상화하고, 하나의 ScreenUI 인터페이스로 묶는게 적절한 추상화로 보인다.
--> 조립을 위한 재사용을 다형성(인터페이스)로 기존 sw로직의 변경 없이 구현체 변경으로 런타임 동작을 바꾸기 위해 추상화와 다형성이 필요한 것으로 정리가 된다.
어떤 메뉴를 선택하였을 때 위 2가지 동작은 메뉴 3,4,5가 추가되더라고 동일하게 동작을 취한다.
메뉴 클릭 시 공통 동작 표현을 위하여 ScreenUI 인터페이스를 정의하고, 아래 2개 method를 정의함
show() : 메뉴 버튼 클릭 시 실행될 메서드, 특정 메뉴에 해당하는 알맞은 화면을 보여주기 위해 사용
handleButton1Click() : 버튼 1이 눌렸을 때 실행될 메서드
public interface ScreenUI{
public void show();
public void handleButton1Click();
}
메뉴 별로 화면에 보이는 구성 요소와 버튼1 클릭을 처리하는 로직이 다르므로 아래 코드와 같이 ScreenUI 인터페이스를 구현한 클래스를 작성한다.
class Menu1ScreenUI implements ScreenUI{
@Override
public void show() {
System.out.println("메뉴1 화면으로 전환");
}
@Override
public void handleButton1Click() {
System.out.println("메뉴1 화면의 버튼1 처리");
}
}
class Menu2ScreenUI implements ScreenUI{
@Override
public void show() {
System.out.println("메뉴2 화면으로 전환");
}
@Override
public void handleButton1Click() {
System.out.println("메뉴2 화면의 버튼1 처리");
}
}
추상화와 다형성을 적용하여 ScreenUI 인터페이스를 만들고, 인터페이스를 구현한 concreate 클래스를 활용해서 main 영역에서 아래 코드에서 주석(//) 처리 된 부분과 비교하여 좀 더 객체지향적으로 구현할 수 있다.
주석 처리 된 부분처럼 한 클래스에 모두 구현하면, 새로운 기능이 추가될 때마다 if 조건문이 늘어나고 따라서 코드가 복잡해지며 이런 사항들이 쌓일 수록 점점 더 코드 수정이 어렵게 된다.
-> 직관적으로 설명하자면, 한 클래스에 여러 기능의 코드가 함께 있다면, 특정 기능을 분석하는 과정에서 불필요하게 다른 기능의 코드도 분석하게 될 가능성이 높고, 이것은 분석과 기능 개발 시간을 증가시키는 요인이 된다.
추상화와 다형성을 이용하여 인터페이스와 concreate 클래스를 생성하여 구현한 경우는, 클래스 개수는 증가하였지만 메뉴 관련 코드들이 알맞게 분리된 것을 볼 수 있다.
public class Main {
public static ScreenUI currentScreen = null;
public static void main(String[] args) {
// TODO Auto-generated method stub
menuClicked("menu1");
menuClicked("menu2");
buttonClicked();
}
public static void menuClicked(String menu) {
if("menu1".equalsIgnoreCase(menu)) {
currentScreen = new Menu1ScreenUI();
currentScreen.show();
}
else if("menu2".equalsIgnoreCase(menu)) {
currentScreen = new Menu2ScreenUI();
currentScreen.show();
}
}
public static void buttonClicked() {
if(currentScreen == null) {
return;
}
currentScreen.handleButton1Click();
}
// private static String currentMenu = null;
//
// public static void clicked(String menu) {
// if("menu1".equalsIgnoreCase(menu)) {
// changeUIToMenu1();
// }
// else if("menu2".equalsIgnoreCase(menu)) {
// changeUIToMenu2();
// }
// else if("button1".equalsIgnoreCase(menu)){
// if(currentScreen == null) {
// return;
// }
// if(currentMenu.equals("menu1")) {
// processButton1WhenMenu1();
// }
// else if(currentMenu.equals("menu2")) {
// processButton1WhenMenu2();
// }
// }
// }
//
// private static void processButton1WhenMenu2() {
// System.out.println("메뉴2 화면의 버튼1 처리");
// }
//
// private static void processButton1WhenMenu1() {
// System.out.println("메뉴1 화면의 버튼1 처리");
// }
//
// private static void changeUIToMenu2() {
// currentMenu = "menu2";
// System.out.println("메뉴2 화면으로 전환");
// }
//
// public static void changeUIToMenu1() {
// currentMenu = "menu1";
// System.out.println("메뉴1 화면으로 전환");
// }
}
'책 내용 정리 > [책] 개발자가 반드시 정복해야 할 객체지향과 디자인 패턴' 카테고리의 다른 글
[6] DI와 서비스 로케이터 (0) | 2023.03.04 |
---|---|
[5] 설계 원칙 : SOLID (0) | 2023.03.01 |
[4] 코드 재사용은 상속보다는 조립 (0) | 2023.03.01 |
[3] 다형성, 추상타입 (0) | 2023.02.27 |
[2] 객체 지향, 다형성, 추상화, 캡슐화, 객체, 메시지, 객체 지향 설계 과정 (0) | 2023.02.25 |
댓글