이터레이터 패턴
컬렉션(List, Set, Map 등)은 데이터를 저장하는 방식이 모두 다르다.
이터레이터 패턴은 데이터를 어떻게 저장하는지 몰라도(캡슐화),
그 안의 요소들을 하나씩 꺼내는 방법만 표준화하는 패턴이다.
사용하는 이유는 자료구조가 변경되어도(예: ArrayList -> LinkedList)
순회 로직 자체를 수정할 필요가 없다.
컬렉션 내부의 복잡한 구현(트리 구조, 해시 테이블 등)을
외부에 노출하지 않고도 안전하게 요소를 전달할 수 있다.
Java 17 예시
java.util.Iterator 인터페이스를 통해import java.util.Iterator;
import java.util.List;
public class IteratorExample {
public static void main(String[] args) {
// ArrayList 형태로 저장된다.
List<String> fruits = List.of("Apple", "Banana", "Orange");
// 표준 이터레이터 사용 (자료구조를 몰라도 순회 가능)
Iterator<String> iterator = fruits.iterator();
while (iterator.hasNext()) {
String fruit = iterator.next();
System.out.println("과일: " + fruit);
}
for (String fruit : fruits) {
System.out.println("과일은: " + fruit);
}
}
}
옵저버 패턴
어떤 객체의 상태가 변할 때
그와 연관된 다른 객체들에게 자동으로 알림을 보내는
1:N 관계의 디자인 패턴이다.
사용하는 이유는 주체(Subject)와 관찰자(Observer)가
서로를 구체적으로 알 필요가 없다(느슨한 결합).
상태 변화를 실시간으로 반영해야 하는
이벤트 기반 시스템(예: 주식 차트, 푸시 알림)에 적합하다.
Java 17 예시
Observable는 Deprecated(권장되지 않음) 되었기에ApplicationEvent 등을 사용하는 것이 현대적이다.import java.util.ArrayList;
import java.util.List;
// 옵저버 인터페이스
interface Observer {
void update(String message);
}
// 주체 (Subject)
class NewsChannel {
private final List<Observer> observers = new ArrayList<>();
public void addObserver(Observer o) { observers.add(o); }
public void notifyObservers(String news) {
for (Observer o : observers) {
o.update(news);
}
}
}
// 실행 예시
public class ObserverExample {
public static void main(String[] args) {
NewsChannel channel = new NewsChannel();
// 익명 클래스 또는 람다를 사용한 옵저버 등록
channel.addObserver(msg -> System.out.println("구독자 A 수신: " + msg));
channel.addObserver(msg -> System.out.println("구독자 B 수신: " + msg));
channel.notifyObservers("새로운 기능 출시");
}
}
노출 모듈 패턴
자바스크립트의 태생적 한계: 예전 자바스크립트는 모든 코드가
전역(Global)에 노출 되었기에 내가 만든 count 변수가
남이 만든 count 변수와 충돌해서 값이 멋대로 바뀌는 대참사가 빈번했다.
해결책: 함수 안에 변수를 가두고(클로저)
밖에서 쓰고 싶은 것만 객체에 담아 노출 시키기로 약속한 것이다.
자바에서는 이 철학이 클래스의 접근 제어자로 이미 녹아들어 있다.
비공개(Private): "내부 부품".
외부에서 건드리면 고장 날 수 있는 로직이나 데이터이다.
공개(Public/Interface): "리모컨 버튼". 사용자가 눌러야 할 최소한의 기능이다.
public class VendingMachine {
// 숨겨진 것 (Private)
private int moneyInside = 0;
// 내부 로직은 건드릴 수 없게 private으로 막아 놓음.
private void verifyCoin(int coin) {
System.out.println(coin + "원이 유효한지 검사 중...");
}
// 노출된 것 (Public): 사용자가 볼 수 있는 '버튼'만 공개
public void insertCoin(int coin) {
verifyCoin(coin); // 내부 로직 호출
this.moneyInside += coin;
System.out.println("코인이 투입되었습니다.");
}
public String pushButton() {
if (moneyInside >= 500) {
return "콜라";
}
return "잔액 부족";
}
}
MVVM 패턴
Model (데이터와 비즈니스 로직)
애플리케이션에서 사용하는 실제 데이터와 그 데이터를 처리하는 로직이다. (DB, API 응답, Service 레이어 등)
UI가 어떻게 생겼는지 전혀 모른다.
오직 "데이터는 무엇인가?"에만 집중한다.
View (사용자 인터페이스)
사용자에게 보여지는 화면(UI) 그 자체이다.
비즈니스 로직을 포함하지 않는다.
오직 "어떻게 보여줄 것인가?"와
"사용자의 입력(클릭 등)을 어떻게 받을 것인가?"만 담당한다.
ViewModel (상태 관리와 중재자)
View를 위한 Model이다.
View에 표시될 데이터를 가공하고, View의 상태를 유지한다.
가장 중요한 점은 ViewModel은 View를 참조하지 않는다.
즉, "내 데이터를 누가 가져가는지" 몰라도 된다.
대신 View가 ViewModel의 데이터를 관찰(Observe)하고 있다가
값이 변하면 스스로 화면을 갱신한다.
왜 MVVM을 사용하는가?
기존 MVC 패턴에서는 컨트롤러가
View와 Model 사이를 일일이 간섭해야 했다.
하지만 MVVM에서는 View가 ViewModel의 데이터에
딱 붙어(Data Binding) 있어서
ViewModel의 데이터만 바뀌면 화면은 알아서 바뀐다.
덕분에 UI 코드가 매우 단순해진다.
"UI 없이도 로직을 테스트하기 위해서" (테스트 용이성)
ViewModel은 View(화면)에 대한 코드가 한 줄도 없다.
따라서 화면을 직접 띄우지 않고도
"데이터가 제대로 가공되는지", "상태가 잘 변하는지"를
JUnit 같은 도구로 완벽하게 테스트할 수 있다.