루비로 배우는 객체지향 디자인 - 4장

<aside> 💡 참고: 타입스크립트는 기본적으로 구조적 타이핑을 지원하기 때문에 엄밀히 따지면 오리 타입을 지원한다고 할 수 있다. 오리 타입을 활용하면 컴파일러가 철저하게 타입을 검사하는 것을 상쇄한다고 볼 수도 있으나, 상황에 따라 유연한 인터페이스를 구성하는데 사용할 수 있을 것이다. (일단 예제는 기존처럼 JS 로 작성)

</aside>

오리 타입으로 비용 줄이기

class Trip {
  constructor({ bicycles, customers, vehicle }) {
    this.bicycles = bicycles;
    this.customers = customers;
    this.vehicle = vehicle;
  }

  // ...

  prepare(mechanic) {
    mechanic.prepareBicycles(this.bicycles);
  }

  // ...
}

class Mechanic {
  prepareBicycles(bicycles) {
    bicycles.forEach((bicycle) => this.prepareBicycle(bicycle));
  }

  prepareBicycle(bicycle) {
    // ...
  }
}
class Trip {
  constructor({ bicycles, customers, vehicle }) {
    this.bicycles = bicycles;
    this.customers = customers;
    this.vehicle = vehicle;
  }

  // ...

  prepare(preparers) {
    preparers.forEach((preparer) => {
      if (preparer instanceof Mechanic) {
        preparer.prepareBicycles(this.bicycles);
      } else if (preparer instanceof TripCoordinator) {
        preparer.buyFood(this.customers);
      } else if (preparer instanceof Driver) {
        preparer.gasUp(this.vehicle);
        preparer.fillWaterTank(this.vehicle);
      }
    })
  }

  // ...
}

class TripCoordinator {
  buyFood(customers) {
    //...
  }
}

class Driver {
  gasUp(vehicle) {
    // ...
  }

  fillWaterTank(vehicle) {
    // ...
  }
}
class Trip {
  constructor({ bicycles, customers, vehicle }) {
    this.bicycles = bicycles;
    this.customers = customers;
    this.vehicle = vehicle;
  }

  // ...

  prepare(preparers) {
    preparers.forEach((preparer) => {
      preparer.prepareTrip(this);
    });
  }

  // ...
}

class Mechanic {
  prepareTrip(trip) {
    trip.bicycles.forEach((bicycle) => this.prepareBicycle(bicycle));
  }

  prepareBicycle(bicycle) {
    // ...
  }
}

class TripCoordinator {
  prepareTrip(trip) {
    this.buyFood(trip.customers);
  }

  buyFood(customers) {
    //...
  }
}

class Driver {
  prepareTrip(trip) {
    const vehicle = trip.vehicle;
    this.gasUp(vehicle);
    this.fillWaterTank(vehicle);
  }

  gasUp(vehicle) {
    // ...
  }

  fillWaterTank(vehicle) {
    // ...
  }
}
// 예시 1
if (preparer instanceof Mechanic) {
  preparer.prepareBicycles(this.bicycles);
} else if (preparer instanceof TripCoordinator) {
  preparer.buyFood(this.customers);
} else if (preparer instanceof Driver) {
  preparer.gasUp(this.vehicle);
  preparer.fillWaterTank(this.vehicle);
}

// 예시 2
if (preparer.hasOwnProperty('prepareBicycles')) {
  // ...
} else if (preparer.hasOwnProperty('buyFood')) {
  // ...
}
// ...