정의
요구 사항을 객체로 캡슐화 할 수 있으며, 매개변수를 써서 여러 가지 다른 요구 사항을 집어넣을 수도 있습니다. 또한 요청 내역을 큐에 저장하거나 로그로 기록할 수도 있으며, 작업취소 기능도 지원 가능 합니다.
어떤 작업을 요청한 쪽하고 그 작업을 처리한 쪽을 분리시킬 수 있다.

브레인 파워
커맨드 패턴 디자인을 사용했을 때 작업을 요구한 인보커와 작업을 처리하는 리시버가 어떤 식으로 분리되는 걸까요?
Invoker ---> Interface(Command) ---> Receiver
구성(Composition) 을 통해서 분리되어 있다.??

Null Object
클라이언트 쪽에서 null을 처리하지 않아도 되도록 하고 싶을 때 널 객체를 활용

Command noCommand = new NoCommand();
onCommand = noCommand
// 널 객체를 사용하면 if 문을 생략하고 사용할 수 있음.
if (onCommand != null)
    onCommand.execute();

다른 커맨드를 실행시킬수 있는 새로운 종류의 커맨드를 만들어서 여러 가지 커맨드를 한꺼번에 실행시킬 수 있는 생각
매크로커맨드
public class MacroCommand implements Command {
    Command[] command;
    public MacroCommand(Command[] command) {
        this.command = command;
    }
    public void execute() {
        for (int i = 0; i < command.length; i++) {
            command[i].execute();
        }
    }
    public void undo() {
        for (int i = 0; i < command.length; i++) {
            command[i].undo();
        }
    }
}


객체지향 원칙(디자인 원칙)
1. 애플리케이션에서 바뀌는 부분을 찾아내서 바뀌지 않는 부분으로부터 분리 시켜 캡슐화 한다.
2. 상속보다는 구성을 활용한다.
3. 구현이 아닌 인터페이스에 맞춰서 프로그래밍 한다.
4. 서로 상호작용을 하는 객체 사이에서는 가능하면 느슨하게 결합하는 디자인을 사용해야 한다.
5. 클래스는 확장에 대해서는 열려 있지만 변경에 대해서는 닫혀 있어야 한다.(OCP : Open-Closed Principle)
6. 추상화된 것에 의존하도록 만들어라. 구상 클래스에 의존하도록 만들지 않도록 한다. (의존성 뒤집기 윈칙:Dependency Inversion Principle)

핵심 정리
- 커맨드 패턴을 이용하면 요청을 하는 객체와 그 요청을 수행하는 객체를 분리시킬 수 있습니다.
- 이렇게 분리시키는 과정의 중심에는 커맨드 객체가 있으며, 이 객체가 행동이 들어있는 리시버를 캡슐화 합니다.
- 인보커에서는 요청을 할 때는 커맨드 객체의 execute()메소드를 호출하면 됩니다. execute() 메소드에서는 리시버에 있는 행동을 호출합니다.
- 인보커는 커맨드를 통해서 매개변수화될 수 있습니다.
- execute() 메소드가 마지막으로 호출되기 전의 기존 상태로 되돌리기 위한 작업취소 메소드를 구현하면 커맨드 패턴을 통해서 작업취소 기능을 지원할 수도 있습니다.
- 매크로 커맨드는 커맨드를 확장해서 여러 개의 커맨드를 한꺼번에 호출할 수 있게 해주는 간단한 방법입니다. 매크로 커맨드에서도 어렵지 않게 작업취소 기능을 지원할 수 있습니다.
- 프로그래밍을 하다 보면 요청자체를 리시버한테 넘기지 않고 자기가 처리하는 "스마트" 커맨드 객체를 사용하는 경우도 종종 있습니다.
- 커맨드 패턴을 활용하여 로그및 트랜잭션 시스템을 구현하는 것도 가능합니다.

Posted by outliers
,

Singleton Pattern
정의
해당 클래스의 인스턴스가 하나만 만들어 지고, 어디서든 그 인스턴스에 접근할 수 있도록 하기 위한 패턴입니다.

싱글톤 패턴 예
public class Singleton {
    private static Singleton instance;

    private Singleton() {}
    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

위와 같이 사용 할 경우 멀티 스레드 환경에서 여러개의 인스턴스가 생성 될 수 있습니다. 그래서 getInstance() 에 synchronized 를 사용해서 스레드 환경에서 발생되는 문제를 해결 할 수 있습니다. 문제는 해결되긴 하지만 동기화를 하면 속도가 느려지는 문제가 발생 합니다. 동기화가 꼭 필요한 시점은 인스턴스를 만드는 그 시점 한 번 뿐이지만 아래와 같이 사용을 하면 불필요한 오버헤드만 증가됩니다.
public class Singleton {
    private static Singleton instance;	
    private Singleton() {}	
    /**
     * getInstance()에 synchronized 키워드만 추가하면 한 스레드가 
     * 메소드 사용을 끝내기 전까지 다른 스레드는 기다려야 합니다.
     * 즉, 두 스레드가 이메소드를 동시에 실행시킬 수 없습니다.
     */
    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

싱글톤을 사용하기 위한 방법
1. getInstance() 의 속도가 그리 중요하지 않으면 그냥 동기화를 사용한다.
2. 인스턴스를 필요할 때 생성하지 말고 처음부터 만들어 버린다.

public class Singleton {
    private static Singleton instance = new Singleton();
    private Singleton() {}
    public static Singleton getInstance() {
        return instance;
    }
}

3. DCL(Double-Checking Locking)을 써서 getInstance()에서 동기화되는 부분을 줄인다.
public class Singleton {
    // 1.5 이전의 버전에서는 volatile 키워드를 사용 할 수 없습니다.
    private volatile static Singleton instance;
    private Singleton() {}
    public static Singleton getInstance() {
        if (instance == null) {
            // 이 방법을 사용 하면 처음에 한번만 동기화가 된다.
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

Posted by outliers
,

객체 생성을 처리하는 클래스를 팩토리라고 부릅니다.

Simple Factory
객체를 생성하는 일을 전담하는 클래스

public class PizzaStore {
    Pizza orderPizza(String type) {
        Pizza pizza;
        if (type.equals("cheese")) {
            pizza = new CheesePizza();
        } else if (type.equals("pepperoni")) {
            pizza = new PepperoniPizza();
        }
        pizza.prepare(); 
        pizza.bake(); 
        piaaz.cut();
        pizza.box();
        reutnr pizza;
    }
}

상황에 따로 코드가 변경되기 때문에 바뀌는 부분과 바뀌지 않는 부분을 분리 한 후 캡슐화를 한다.
Simple Factory 적용해서 위와 같은 문제점을 수정한다.
public class SimplePizzaFactory {
    public Pizza create Pizza(String type) {
        Pizza pizza = null;
        if (type.equals("cheese")) {
            pizza = new CheesePizza();
        } else if (type.equals("pepperoni")) {
            pizza = new PepperoniPizza();
        }
        return pizza;
    }
}

분점에서 PizzaStore 를 활용하여 NYPizzaFactory라는 factory 를 만들어서 뉴욕식 피자를 만드는 팩토리를 사용한다.
NYPizzaFactory nyFactory = new NYPizzaFactory();
PizzaStore nyStore = new PizzaStore(nyFactory);
nyStore.order("cheese");


문제점
분점에서 독자적인 방법들을 사용하기 시작했습니다.
굽는 방식이 달라진다거나 피자를 자르는 것을 까먹어 버리는일, 이상한 피자 상자를 사용 등
그래서 피자 가게와 피자 제작 과정 전체를 하나로 묶어주는 프레임워크를 만들어야 겠다는 결론에 도달했습니다.

피자를 만드는 활동 자체는 전부 PizzaStore 클래스에 국한시키면서도 분점마다 고유의 스타일을 살릴 수 있도록 하는 방법이 있습니다.

createPizza() 를 PizzaStore에 다시 넣고 그 메소드를 추상 메소드로 선언하고, 각 분점마다 고유의 스타일에 맞게 PizzaStore의 서브클래스를 만들도록 할 것입니다.

public abstract class PizzaStore {

    public Pizza orderPizza(String type) {
        Pizza pizza;

        pizza = createPizza(type);

        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        return pizza;
    }
    abstract Pizza createPizza(String type);
}

팩토리 메서드 패턴(Factory Method Pattern)

정의

객체를 생성하기위한 인터페이스를 정의하는데, 어떤 클래스의 인스턴스를 만들지는 서브클래스에서 결정하게 만듭니다. 팩토리 메소드 패턴을 이용하면 클래스의 인스턴스를 만드는 일을 서브클래스에게 맡기는 것이죠.
-> 클라이언트 코드와 인스턴스를 만들어야 할 구상 클래스를 분리시켜야 할 때, 어떤 구상 클래스를 필요로 하게 될지 미리 알 수 없는 경우에도 매우 유용합니다.

"메서드 팩토리 패턴에서는 어떤 클래스의 인스턴스를 만들지를 서브클래스에서 결정한다?
서브클래스에서 실제로 뭔가를 "결정"하는 것이 아니라, 우리가 선택하는 PizzaStore의 서브클래스 종류에 따라 결정되는 것이지만, 만들어지는 피자의 종류를 해당 서브클래스에서 결정한다고 할 수도 있겠죠
수퍼클래스에 있는 orderPizza()에서는 어떤 피자가 만들어 지는지 전혀 알 수 없다는 점을 잘 이해해야 합니다.
Pizza 인스턴스를 만드는 일을 이제 팩토리 역할을 하는 메소드에서 맡아서 처리 합니다.
팩토리 메소드는 객체 생성을 처리하며, 팩토리 메소드를 이용하면 객체를 생성하는 작업을 서브클래스에 캡슐화시킬 수 있습니다. 수퍼클래스에 있는 클라이언트 코드와 서브클래스에 있는 객체 생성 코드를 분리시킬 수 있습니다.

모든 팩토리 패턴에서는 객체 생성을 캡슐화합니다. 팩토리 메소드 패턴에서는 서브클래스에서 어떤 클래스를 만들지를 결정하게 함으로써 객체 생성을 캡슐화 합니다.

객체 생성 코드를 전부 한 객체 또는 메소드에 집어넣으면 코드에서 중복되는 내용을 제거할 수 있고, 나중에 관리할 때도 한군데에만 신경을 쓰면 됩니다. 구현이 아닌 인터페이스를 바탕으로 프로그래밍을 할 수 있게 되고, 그 결과 유연성과 확장성이 뛰어난 코드를 만들 수 있게 됩니다.

Simple Factory 와 Factory Method 차이점
간단한 팩토리를 사용할 때는 팩토리가 PizzaStore 안에 포함되는 별개의 객체이다.
팩토리 메서드 패턴을 이용하면 어떤 구현을 사용할지를 서브클래스에서 결정하는 프레임워크를 만들 수 있다는 결정적인 차이점이 있다.
간단한 팩토리에서는 객체생성을 캡슐화하는 방법을 사용하긴 하지만 팩토리 메소드 패턴처럼 강력한 유연성을 제공하지는 못한다. 생성하는 제품을 마음대로 변경할 수 없기 때문이다.

객체지향 원칙(디자인 원칙)
1. 애플리케이션에서 바뀌는 부분을 찾아내서 바뀌지 않는 부분으로부터 분리 시켜 캡슐화 한다.
2. 상속보다는 구성을 활용한다.
3. 구현이 아닌 인터페이스에 맞춰서 프로그래밍 한다.
4. 서로 상호작용을 하는 객체 사이에서는 가능하면 느슨하게 결합하는 디자인을 사용해야 한다.
5. 클래스는 확장에 대해서는 열려 있지만 변경에 대해서는 닫혀 있어야 한다.(OCP : Open-Closed Principle)
6. 추상화된 것에 의존하도록 만들어라. 구상 클래스에 의존하도록 만들지 않도록 한다. (의존성 뒤집기 윈칙:Dependency Inversion Principle)

3번과 6번이 비슷하지만 의존성 뒤집기 원칙에서는 추상화를 더 많이 강조 합니다. 이 원칙에는 고수준 구성요소가 저수준 구성요소에 의존하면 안 된다는 것이 내포되어 있습니다. 항상 추상화에 의존하도록 만들어야 합니다.
고수준 구성요소는 다른 저수준 구성요소에 의해 정의되는 행동이 들어있는 구성요소를 뜻합니다.
예를 들어, PizzaStore의 행동은 Pizza에 의해 정의되기 때문에 PizzaStore는 고수준 구성요소라고 할 수 있고, Pizza 는 저수준 구성요소라고 할 수 있습니다.

의존성 뒤집기 원칙을 지키는데 도움이 될만한 가이드 라인
- 어떤 변수에도 구상 클래스에 대한 레퍼런스를 저장하지 맙시다.
- 구상 클래스에서 유도된 클래스를 만들지 맙시다.
- 베이스 클래스에 이미 구현되어 있던 메소드를 오버라이드 하지 맙시다.


추상 팩토리 패턴

정의
인터페이스를 이용하여 서로 연관된, 또는 의존하는 객체를 구상 클래스를 지정하지 않고도 생성할 수 있습니다.
구상 클래스는 서브 클래스에 의해 만들어 집니다.
-> 클라이언트에서 서로 연관된 일련의 제품들을 만들어야 할 때, 즉 제품군을 만들어야 할 때

팩토리 메소드 패턴과 추상 팩토리 패턴
두 패턴 모두 객체 생성을 캡슐화해서 애플리케이션의 결합을 느슨하게 만들고, 특정 구현에 덜 의존하도록 만들 수 있다.
팩토리 메소드 패턴
- 상속을 통해서 객체를 생성
- 클라이언트와 구상 형식을 분리시켜주는 역할을 한다.
- 서브클래스에서 만드는 구상 형식을 활용하는 추상 생산자에서 코드를 구현한다.
- 클라이언트 코드와 인스턴스를 만들어야 할 구상 클래스를 분리시켜야 할 때, 어떤 구상 클래스를 필요로 하게 될지 미리 알 수 없는 경우에도 유용하다.

추상 팩토리 패턴
- 객체 구성을 통해서 생성
- 일련의 연관된 제품을 하나로 묶을 수 있다.
- 제품을 추가하려면 인터페이스를 바꾸어야 한다.
- 팩토리 메소드 패턴을 사용하여 제품을 생성하는 경우가 있다.
- 클라이언트에서 서로 연관된 일련의 제품들을 만들어야 할 때, 즉 제품군을 만들어야 할 때 사용

핵심 정리
- 팩토리를 쓰면 객체 생성을 캡슐화할 수 있습니다.
- 간단한 팩토리는 엄밀하게 말해서 디자인 패턴은 아니지만, 클라이언트와 구상 클래스를 분리시키기 위한 간단한 기법으로 활용할 수 있습니다.
- 팩토리 메소드 패턴에서는 상속을 활용합니다. 객체 생성이 서브클래스에게 위임되죠. 서브클래스에서는 팩토리 메소드를 구현하여 객체를 생산합니다.
- 추상 팩토리 패턴에서는 객체 구성을 활용합니다. 객체 생성이 팩토리 인터페이스에서 선언한 메소들에서 구현되죠.
- 모든 팩토리 패턴에서는 애플리케이션의 구상 클래스에 대한 의존성을 줄여줌으로써 느슨한 결합을 도와줍니다.
- 팩토리 메소드 패턴에서는 어떤 클래스에서 인스턴스를 만드는 일을 서브클래스한테 넘깁니다.
- 추상 팩토리 패턴은 구상 클래스에 직접 의존하지 않고도 서로 관련된 객체들로 이루어진 제품군을 만들기 위한 용도로 쓰입니다.
- 의존성 뒤집기 원칙을 따르면 구상 형식에 대한 의존을 피하고 추상화를 지향할 수 있습니다.
- 팩토리는 구상 클래스가 아닌 추상 클래스/인터페이스에 맞춰서 코딩할 수 있게 해주는 강력한 기법입니다.
Posted by outliers
,