독서 기록/디자인패턴

[디자인패턴] 헤드퍼스트 디자인패턴 Chap.4 (Feat.팩토리)

JoJobum 2022. 10. 10.

new를 사용하지 않을 수는 없음

 

디자인 원칙

OCP(Open-Closed Principle): 클래스는 확장에는 열려있어야 하지만 변경에는 닫혀 있어야 한다.

 

인터페이스 기반이면 어떤 클래스든 인터페이스를 구현하면 사용할 수 있음 (다형성)

구상 클래스를 사용하면 구상 클래스가 추가될 때마다 코드 수정 필요 => 변경에 닫혀있게 됨

=> 새로운 구상 형식을 써서 확장할 때는 다시 변경에 열릴 수 있게 하자

 

Phone getPhone(String model){
    Phone phone;
    
    // 폰 종류가 늘어날 때마다 코드가 바뀌어야 하는 부분
    if(model.equals("galaxy s10"){
    	phone = new GalaxyS10();
    }else if(model.equals("iphone 14"){
    	phone = new IPhone14();
    }
    
    // 공통된 부분    
    phone.init()

    return phone;
}

이부분에서 인스턴스를 만드는 구상 클래스를 선택하는 부분이 코드가 계속 바뀌는 즉, 변경에 닫혀 있는 부분

이를 개선해보자

 

객체 생성을 담당하는 클래스를 Factory라 함

public class PhoneFatory {
    public Phone createPhone(String model){
       Phone phone = null;
       // 폰 종류가 늘어날 때마다 코드가 바뀌어야 하는 부분
       if(model.equals("galaxy s10"){
    	   phone = new GalaxyS10();
       }else if(model.equals("iphone 14"){
    	   phone = new IPhone14();
       }
       return phone;
    }
}

이렇게 캡슐화를 하면 => 구현을 변경시 여기저기 고칠 필요 없이 팩토리 클래스만 고칠 수 있게 됨

 

public class PhoneStore{
    PhoneFactory factory;
    
    public PhoneStore(PhoneStore factory){
        this.factory = factory;
    }
    
    public Phone getPhone(String type){
        Phone phone;
        
        phone = factory.createPhone(type);
        
        phone.init();
        return phone;
    }
}

위의 상황에서 필요에 따라 팩토리의 종류를 늘리서 사용할 수도 잇음

좀더 확장해보자면 

 

public abstract class PhoneStore{
	// 추상 메서드를 추가함으로서 추상 클래스가 됨
    abstract Phone createPhone(String type);
    
    public Phone getPhone(String type){
        Phone phone;
        
        // 팩토리 객체가 아닌 phoneStore의 createPhone호출
        phone = createPhone(type);
        
        phone.init();
        return phone;
    }
}

PhoneStore를 추상클래스로 만드는 것을 통해 PhoneStore의 서브 클래스들을 만들고 createPhone을 입맛에 맞게 구현할 수 있다.

 

팩토리 메소드 패턴 : 객체를 생성할 때 필요한 인터페이스를 만들어 어떤 클래스의 인스턴스를 만들지는 것을 서브 클래스에서 결정하도록 함. 

 

구상 클래스 의존성을 줄이면 좋다

의존성 뒤집기 원칙(Dependency Inversion Principle): 추상화된 것에 의존하고 구상 클래스에 의존하지 않게 하라 

팩토리 메소드 패턴을 적용하여 고수준 구성요소인 PhoneStore와 저수준 구성 요소인 Phone 객체 모두가 추상 클래스인 Phone에 의존하게 된다. 

 

위와 같은 의존성 뒤집기 법칙을 지키는 가이드라인( 다 지키는 것은 사실상 불가능한 일)

 

1. 변수에 구상 클래스의 레퍼런스를 저장하지 말자, new 연산자를 사용하면 구상 클래스의 래퍼런스를 사용하게 되기에 팩토리를 사용하자

 

2. 구상 클래스에서 유도된 클래스를 만들지 말자, 구상 클래스에서 유도된 클래스를 만들면 특정 구상 클래스에 의존하게 되게 인터페이나 추상 클래스로부터 클래스를 만들자  

 

3. 베이스 클래스에 이미 구현되어 있는 메소드를 오버라이드하지 말자, 베이스 클래스에서 메소드를 정의할 때는 모든 서브클래스에서 공유할 수 있는 것만 정의하자

 

 

반응형

댓글