3주차 2 - CodingInterviewStudy/CrackingTheCodingInterview GitHub Wiki
실제 생활에서 접할 수 있는 객체들을 구현하는 클래스와 메서드를 대략적으로 그려보는 문제이다. 이런 문제들을 통해 지원자들이 어떤 코딩 스타일을 갖고 있는지 알 수 있다.
객체지향 설계 관련 문제들은 대개 고의적으로 모호성을 띄고있다. 지원자가 스스로 가정을 만들어내고 질문을 통해 명확히 내가가는 과정을 보고싶어하기 때문이다.
질문을 받으면, 먼저 누가 그것을 사용하고, 어떻게 사용할 것인지 질문을 던져야한다. 질문에 따라서는 육하원칙에 따른 질문을 던져야 할 때도 있다.
커피머신을 예로 들면 시간당 수백명이 사용하며 열가지 이상의 제품을 만들어내는 대규모 식당에 설치되는 머신일 수 있고, 아니면 어르신들만이 사용하는 블랙 커피만 만드는 간단한 기계일 수 있다.
어떤 용도로 쓰냐에 따라 설계 자체가 완전히 뒤바뀐다.
핵심 객체(Domain)가 무엇인지 생각해봐야 한다. 예를 들면 식당의 경우 핵심 객체로는 Table, Guest, Order 등이 있다.
핵심 객체 사이의 관계를 분석한다. 어떤 객체가 어떤 객체에 속해있는지, 상속관계가 있는지, N:N 관계인지 1:N 관계인지.
식당의 경우 다음과 같이 설계할 수 있다.
- Party는 Guest 배열을 갖고 있어야 한다.
- Server와 Host는 Employee를 상속받는다.
- 각 Table은 Party를 하나만 가질 수 있지만, 각 Party는 Tables를 여러개 가질 수 있따.
- Restaurant에 Host는 한명 뿐이다.
종종 가정이 다를 경우가 있다. 해당 설계는 면접관과 의논해 보자.
객체가 수행해야 하는 핵심행동들에 대해 생각하고, 어떻게 상호작용할지 따져본다.
가령 하나의 Party가 Restaurant에 입장하고, 한 Guest가 Host에게 Table을 부탁하는 경우이다. Host는 Reservation을 살펴본다음 자기라 있으면 해당 Party에 Table을 배정하고, 없다면 Reservation 리스트 맨 마지막에 Party를 추가한다. 다른 Party가 식사를 마치고 떠나면 한 Table이 비게되고 그때 최상위 Party에게 배정될 것이다.
디자인 패턴의 종류는 굉장히 많다. 특정 문제에 가장 정합한 디자인 패턴을 찾으려는 함정에 빠지지 않도록 하자.
필요하다면 직접 만들자, 특별한 경우 기존 패턴이 적합할 수 있지만 많은 경우엔 그렇지 않다.
싱글톤 패턴은 어떤 클래스가 오직 하나의 객체만을 갖도록 하며, 프로그램 전반에 걸쳐 그 객체 하나만 사용하도록 보장해야 한다.
예를 들어 Restaurant 클래스는 정확히 하나의 객체만 갖도록 구현한다.
public class Printer {
// 외부에 제공할 자기 자신의 인스턴스
private static Printer printer = null;
private Printer() { }
// 자기 자신의 인스턴스를 외부에 제공
public static Printer getPrinter(){
if (printer == null) {
// Printer 인스턴스 생성
printer = new Printer();
}
return printer;
}
public void print(String str) {
System.out.println(str);
}
}스프링의 빈 등록시 이러한 패턴으로 진행된다. 대부분 단위 테스트에 방해되기도 하고 전역변수를 그리 좋아하지 않기 때문에 안티패턴이다.
어떤 클래스의 객체를 생성하기 위한 인터페이스를 제공하되, 하위 클래스에서 어떤 클래스를 생성할지 결정할 수 있도록 도와준다.
- Factory 메서드 자체에 대한 구현은 제공하지 않고, 객체 생성 클래스를 abstract로 선언하고 두는 것
- Factory 메서드를 실제 구현한 Creator 클래스를 만드는 것
public class CardGame {
public static CardGame createCardGame(GameType type) {
if (type == GameType.Poker) {
return new PokerGame();
} else if (type == GameType.BlackJack) {
return new BlackJackGame();
}
return null;
}
}강아지, 금붕어, 독수리의 동물들이 동물원에 있다. 또한 사육사도 동물원에 있다.
각 생물들은 각자 다른 나이를 가지고 있다. 또한 각 생물들은 움직일 수 있는데 강아지는 앞뒤로만 움직일 수 있고, 독수리는 앞뒤로 움직이기도 하고 날수도 있다. 물고기와 사람은 앞뒤로 움직이기도 하고 수영할 수도 있다고 가정한다. 대신 사람은 10m 밑으로 수영하면 위험하다는 알림을 알려주도록 한다.
생물은 동물과 사람으로 나뉘는데 사람은 대화를 할 수 있다는 것이 차이점이다.
사육사는 동물들에게 먹이를 줄 수 있는데 강아지와 고양이와 금붕어는 사료를 먹지만, 독수리는 고기를 먹는다고 가정한다.
또한 현재 나이와 위치를 알려주는 기능을 구현하자.
--결과
강아지은/는 6살이며 현재 위치는 x: 0, y: 0 입니다.
강아지은/는 7살이며 현재 위치는 x: 5, y: 0 입니다.
금붕어은/는 1살이며 현재 위치는 x: 2, y: 0 입니다.
금붕어은/는 2살이며 현재 위치는 x: 10, y: -5 입니다.
독수리은/는 20살이며 현재 위치는 x: 3, y: 0 입니다.
독수리은/는 21살이며 현재 위치는 x: 13, y: 10 입니다.
사람은/는 25살이며 현재 위치는 x: 0, y: 0 입니다.
더 이상 내려가면 위험해요!
사람은/는 26살이며 현재 위치는 x: 7, y: -10 입니다.
사육사는 먹이를 주고 있습니다.
사료를 주었다.
사육사는 먹이를 주고 있습니다.
고기를 주었다.해당 조건을 활용하여 클래스를 구현하라.
답
/* package whatever; // don't place package name! */
import java.util.*;
import java.lang.*;
import java.io.*;
abstract class Creature {
private int x;
private int y;
private int age;
public Creature(int x, int y, int age) {
this.x = x;
this.y = y;
this.age = age;
}
public abstract void printInfo();
public void increaseAge() {
age++;
}
public void move(int xDistance) {
setX(getX() + xDistance);
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
@Override
public String toString() {
return String.format("은/는 %d살이며 현재 위치는 x: %d, y: %d 입니다.", age, x, y);
}
}
interface Talkable {
void talk();
}
interface Flyable {
void fly(int yDistance);
}
interface Swimable {
void swim(int yDistance);
}
interface ZooKeeper {
void feeding(Animal animal);
}
abstract class Animal extends Creature {
public Animal(int x, int y, int age) {
super(x, y, age);
}
}
class Dog extends Animal {
public Dog(int x, int y, int age) {
super(x, y, age);
}
public void move(int xDistance) {
setX(getX() + xDistance);
}
public void printInfo() {
System.out.println("강아지" + toString());
}
}
class Eagle extends Animal implements Flyable {
public Eagle(int x, int y, int age) {
super(x, y, age);
}
@Override
public void fly(int yDistance) {
setY(getY() + yDistance);
}
public void printInfo() {
System.out.println("독수리" + toString());
}
}
class Fish extends Animal implements Swimable {
public Fish(int x, int y, int age) {
super(x, y, age);
}
@Override
public void swim(int yDistance) {
setY(getY() + yDistance);
}
public void printInfo() {
System.out.println("금붕어" + toString());
}
}
abstract class Human extends Creature implements Talkable {
public Human(int x, int y, int age) {
super(x, y, age);
}
@Override
public void talk() {
System.out.println("안녕하세요.");
}
@Override
public void printInfo() {
System.out.println("사람" + toString());
}
}
class Alex extends Human implements ZooKeeper, Swimable {
public Alex(int x, int y, int age) {
super(x, y, age);
}
@Override
public void feeding(Animal animal) {
System.out.println("사육사는 먹이를 주고 있습니다.");
if(animal instanceof Dog || animal instanceof Fish) {
System.out.println("사료를 주었다.");
} else if (animal instanceof Eagle) {
System.out.println("고기를 주었다.");
}
}
@Override
public void swim(int yDistance) {
setY(getY() - yDistance);
if(getY() <= -10) {
System.out.println("더 이상 내려가면 위험해요!");
}
}
}
public class Main {
public static void main(String[] args) {
Dog dog = new Dog(0, 0, 6);
dog.printInfo();
dog.increaseAge();
dog.move(5);
dog.printInfo();
Fish fish = new Fish(2, 0, 1);
fish.printInfo();
fish.increaseAge();
fish.move(8);
fish.swim(-5);
fish.printInfo();
Eagle eagle = new Eagle(3, 0, 20);
eagle.printInfo();
eagle.increaseAge();
eagle.move(10);
eagle.fly(10);
eagle.printInfo();
Alex alex = new Alex(0, 0, 25);
alex.printInfo();
alex.increaseAge();
alex.move(7);
alex.swim(10);
alex.printInfo();
alex.feeding(dog);
alex.feeding(eagle);
}
}