Kiosk 기술 과제 트러블 슈팅
문득 궁금해진 것들.
Cart클레스에 MenuItem을 상속 받아서 사용했었습니다.
그런데 이렇게 하게되면 이전에 제가 오브젝트 및 객체지향 관련 책을 읽었을 당시 상속을 하게 되는 경우를 최대한 지양해라라는 것이 기억이 낫습니다. 그래서 이런 코드를 짜게 되면 어떤 문제점을 초래하는 것일지 생각해봤습니다.
Cart extends MenuItem에 대한 문제점
상속을 지양하라는 이유 ?
Cart extends MenuItem의 문제점
해결
Cart는 MenuItem을 포함하는 조합 관계로 설계하면 되는 것입니다
예) List<MenuItem>
또는 Map<MenuItem, Integer>
외부 코드가 내부 데이터를 직접 수정하지 못하도록 하는 기법입니다.
저의 코드에서
public List<T> getItems() {
return new ArrayList<>(items); // 방어적 복사
}
new ArrayList<>(items)
는 원본 데이터를 복사하여 반환하므로, 외부 코드가 반환된 리스트를 변경해도 원본 데이터에 영향을 미치지 않게 됩니다.이는 너무 당연하고 쉬운 내용이지만, 문득 List에서 Lsit<>로 해두고 ArrayList를 임포트 하면서 쓰는 것을 생각하면서 HashMap과 Map의 관계도 정리했습니다.
Map은 인터페이스이며, HashMap은 Map 인터페이스를 구현한 클래스입니다.
Map<String, String> map = new HashMap<>(); // 인터페이스로 선언
특정 구현체의 메서드가 필요할 때만 HashMap을 사용합니다.
ArrayList와 List의 관계
List<String> list = new ArrayList<>();
ArrayList를 직접 사용하는 경우
ArrayList의 특정 메서드가 필요하거나, 구현체를 변경할 필요가 없을 때 사용합니다.
Cart는 비즈니스 로직(장바구니에 추가, 삭제, 가격 계산 등)을 수행합니다.
비즈니스 로직은 데이터를 처리하는 주된 역할을 하므로 서비스 계층에 위치합니다.
Menu는 데이터(메뉴)를 관리하는 역할만 수행합니다.
데이터의 CRUD(Create, Read, Update, Delete)를 담당하므로 DAO(Data Access Object)로 분류됩니다.
(최종 리팩토링은 List)
기존 코드와 수정 코드의 차이
이전에는 List<CartItem>
구조를 사용했으나, 수정 후 Map<MenuItem, Integer>
구조를 사용했습니다.
List<CartItem>
: 장바구니 항목을 CartItem 객체로 관리.Map<MenuItem, Integer>
: 메뉴와 수량만 관리.장바구니 항목에 추가적인 속성(할인, 옵션 등)을 저장하려면 List<CartItem>
방식이 적합합니다.
단순히 메뉴와 수량만 관리하려면 Map<MenuItem, Integer>
방식이 적합합니다.
다시 말해,
간단한 요구사항/Map.
만약 장바구니에서 메뉴와 수량만 관리한다면 Map<MenuItem, Integer>
이 더 적합합니다.
예를 들어, "햄버거 3개, 감자튀김 2개"처럼 간단히 저장할 때는 Map이 효율적입니다.
복잡한 요구사항/List
장바구니 항목에 추가 정보를 저장하거나 확장성이 중요하다면 List<CartItem>
방식이 더 적합합니다.
예를 들어, "햄버거 (치즈 추가, 매운맛 소스), 감자튀김 (라지 사이즈)" 같은 주문에서는 CartItem을 사용해야 합니다.
그래서 저는 다시 List<CartItem>
으로 사용했습니다.
유지보수성, 확장성 측면에서 해당 구조가 더 적합하다고 생각되었기 때문입니다.
이유)
상속 대신 조합: Cart와 MenuItem의 관계는 "has-a" 관계로 표현해야 합니다.
방어적 복사: 외부 수정으로부터 데이터를 보호하는 중요한 기법입니다.
Map과 HashMap: 인터페이스(Map)를 사용하여 구현체를 유연하게 변경할 수 있습니다.
List와 ArrayList: 인터페이스(List)를 사용하면 유지보수성이 향상됩니다.
Cart와 Menu의 역할: Cart는 비즈니스 로직, Menu는 데이터 관리 역할입니다.
수정된 구조: List<CartItem>
과 Map<MenuItem, Integer>
중 설계 요구사항에 따라 선택하면 됩니다.