Skip to content

Latest commit

 

History

History
195 lines (142 loc) · 4.57 KB

File metadata and controls

195 lines (142 loc) · 4.57 KB

자바스크립트 MV* 패턴

8.1 MVC 패턴

M 모델

모델은 애플리케이션의 데이터를 관리

모델이 변경되었을 때 뷰에 변경사항을 알려주는 역할을 한다.

뷰는 모델에 직접적으로 접근하지 않는다.

V 뷰

뷰는 모델에 대한 시각적인 표현

C 컨트롤러

모델과 뷰를 연결하는 역할

모델과 뷰 사이의 중재자 역할을 한다.

만약 리액트에서 구현한다면?

const userAPI = {
  getUser: async (id: number): Promise<User> => {
    return { id, name: "John", email: "john@example.com" };
  },
  updateUser: async (id: number, name: string): Promise<User> => {
    return { id, name, email: "john@example.com" };
  }
};

class UserModelMVC {
  private user: User | null = null;
  private listeners: Set<() => void> = new Set();

  subscribe(listener: () => void) {
    this.listeners.add(listener);
    return () => this.listeners.delete(listener);
  }

  private notify() {
    this.listeners.forEach(listener => listener());
  }

  async fetchUser(id: number) {
    this.user = await userAPI.getUser(id);
    this.notify();
  }

  async updateName(name: string) {
    if (this.user) {
      this.user = await userAPI.updateUser(this.user.id, name);
      this.notify();
    }
  }

  getUser() { return this.user; }
}

// MVC View
const UserViewMVC = () => {
  const [user, setUser] = useState<User | null>(null);
  const model = useMemo(() => new UserModelMVC(), []);

  useEffect(() => {
    const unsubscribe = model.subscribe(() => {
      setUser(model.getUser());
    });
    model.fetchUser(1);
    return unsubscribe;
  }, [model]);

  if (!user) return <div>Loading...</div>;

  return (
    <div>
      <h2>MVC Pattern</h2>
      <input
        value={user.name}
        onChange={e => model.updateName(e.target.value)}
      />
      <div>{user.email}</div>
    </div>
  );
};

이렇게 되지 않을까?

8.6 MVP 패턴

M 모델

동일

V 뷰

동일

P 프레젠터

모델과 뷰를 연결하는 역할, 뷰에서 이벤트 호출은 프레젠터에서 처리

만약 리액트에서 구현한다면?

class UserModelMVP {
  private user: User | null = null;

  async fetchUser(id: number) {
    this.user = await userAPI.getUser(id);
    return this.user;
  }

  async updateName(name: string) {
    if (this.user) {
      this.user = await userAPI.updateUser(this.user.id, name);
      return this.user;
    }
    return null;
  }
}

class UserPresenter {
  constructor(
    private model: UserModelMVP,
    private setUser: (user: User) => void
  ) {}

  async loadUser(id: number) {
    const user = await this.model.fetchUser(id);
    if (user) this.setUser(user);
  }

  async updateName(name: string) {
    const user = await this.model.updateName(name);
    if (user) this.setUser(user);
  }
}

// MVP View
const UserViewMVP = () => {
  const [user, setUser] = useState<User | null>(null);
  const presenterRef = useRef<UserPresenter>();

  useEffect(() => {
    const model = new UserModelMVP();
    presenterRef.current = new UserPresenter(model, setUser);
    presenterRef.current.loadUser(1);
  }, []);

  if (!user) return <div>Loading...</div>;

  return (
    <div>
      <h2>MVP Pattern</h2>
      <input
        value={user.name}
        onChange={e => presenterRef.current?.updateName(e.target.value)}
      />
      <div>{user.email}</div>
    </div>
  );
};

중간 정리

MVC, MVP 너무 비슷하다라는 느낌을 받았고, 실제 코드를 작성할 때도 뭔가 명확하게 나누기 어렵지 않나 라는 생각이 들었다.

8.8 MVVM 패턴

되게 이해가 잘 안되어서 claude 녀석의 답변을 첨부합니다,,

MVVM은 간단히 말해서 "데이터의 자동 동기화"가 핵심입니다. 실생활에서 은행 ATM을 예로 들어보겠습니다:

Model (통장): 실제 계좌의 잔액 정보를 가지고 있음 ViewModel (은행 직원): 통장의 정보를 화면에 표시할 수 있는 형태로 변환하고 관리 View (ATM 화면): 사용자에게 정보를 보여주고 입력받음

여기서 ViewModel(은행 직원)은:

Model(통장)의 잔액이 변경되면 자동으로 View(화면)에 반영 사용자가 View(화면)에서 입력한 내용을 Model(통장)에 반영 필요한 경우 데이터 형식을 변환 (예: 숫자 → 통화 형식)

이게 맞는 것인지 이따가 여러분들 의견좀 듣겠습니다,,

8.10 MV* 패턴과 리액트

되게 이해가 안 가는게 P.201_L4) MVC로 분류되지 않습니다, ... P.202_L2) 전통적인 MVC 형태로 동작합니다. <- 이게 대체 뭔말인지 .,,,