상위 클래스가 제공하는 기능들을 통해서 하위 클래스에서 행동을 정의한다.

 

12.2 동기

Superpower라는 상위 클래스를 만든 후에 초능력별로 이를 상속받는 클래스를 정의한다고 가정

초능력 클래스가 수십 개가 넘으면 초능력 클래스를 길게 하드코딩 하는 것보다 데이터 기반으로 구현하는게 낫다.

타입 객체(13장), 바이트코드(11장), 인터프리터 같은 패턴을 사용할 수 있다.

 

ㄴ 중복 코드가 많아진다.

ㄴ 거의 모든 게임 코드가 초능력 클래스와 커플링된다.

ㄴ 외부 시스템이 변경되면 초능력 클래스가 깨질 가능성이 높다.

ㄴ 모든 초능력 클래스가 지켜야 할 규칙을 정의하기 어렵다.

class Superpower {
	public:
    	virtual ~Superpower() {}
        
	protected:
    	virtual void activate() = 0; // 추상 샌드박스 메서드
        void move(double x, double y, double z) {
         // 코드..
        }
        void playSound(SoundId sound, double volume) {
         // 코드..
        }
        
        double getHeroX() { }
        double getHeroY() { }
        double getHeroZ() { }
    }
}   

class  SkyLaunch : public Superpower {
	protected:
    	virtual void activate() { // 샌드박스 메서드를 오버라이딩한다. 
        // 하늘로 튀어 오른다.
        // 상위 클래스의 메서드들을 조합하여 기능을 구현한다.
        playSound(SOUND_SPROING, 1.0f); 
        spawnParticles(PARTICLE_DUST, 10);
        move(0, 0, 20);
   	}
};

12.5 주의사항

상위 클래스에 코드가 계속 쌓이는 경향이 있다.

많은 하위 클래스들이 상위 클래스를 통해서 게임 코드에 접근하므로 상위 클래스가 하위 클래스에서 접근하려는 모든 시스템(사운드, 이펙트)과 커플링 된다.

그렇기 때문에 상위 클래스를 조금만 바꿔도 문제가 생기는 하위 클래스가 생길 수 있다. (깨지기 쉬운 상위 클래스 문제)

 

12.7 디자인 결정

어떤 기능을 제공해야 하나?

외부 기능을 전부 상위 클래스에서 제공받으면 상위 클래스가 지나치게 복잡해질 수 있기 때문에 하위 클래스에서 처리할 수 있으면 그렇게 하는 것이 낫기 때문에 상위 클래스가 제공할 기능들을 선택해야 한다.

 

상위 클래스가 제공해야 할 기능

1. 모든 하위 클래스가 영향을 받는 기능

2. 외부 시스템의 상태를 변경하는 함수 (set 함수?)

ㄴ 이러한 함수는 외부 시스템과 강하게 커플링되기 때문에 상위 클래스로 옮겨주어 하위 클래스의 결합도를 낮춰야 한다.

 

메서드를 직접 제공할 것인가? 이를 담고 있는 객체를 통해서 제공할 것인가?

개별 기능들을 전부 메서드화 하여 상위 클래스에 넣으면 메서드가 너무 많아질 수 있기 때문에 역할이 비슷한 기능들을 하나의 클래스에 묶고 그 객체를 반환하는 메서드를 제공하는 방법을 사용할 수 있다.

 

상위 클래스는 필요한 객체를 어떻게 얻는가?

1. 상위 클래스의 생성자 인수로 받기

ㄴ 하위 클래스 생성자도 인수로 받아야 하는 문제가 있다.

 

2. 2단계 초기화

ㄴ 상위 클래스 내부에 init 함수를 두어 필요한 객체를 init 함수의 인자로 받는다.

1단계 : 객체 생성

2단계 : 객체->init(필요한 객체들);

 

3, 정적 객체로 만들기

필요한 객체가 예를 들어 파티클 시스템(싱글턴)이라면 상위 클래스에 정적 객체를 만들고 초기화 했을 때 모든 인스턴스에서 파티클 시스템에 접근할 수 있고, 인스턴스별로 파티클 시스템 객체를 저장할 필요가 없어 메모리 사용량을 줄일 수 있다.

class Superpower {
	public:
    	static void init(ParticleSystem* particles) {
        	particles_ = particles;
        }
       	
        // 샌드박스 메서드와 그 외 다른 기능들...
    
    private:
    	static ParticleSystem* particles_;
};

 

4. 서비스 중개자를 이용하기

상위 클래스가 필요로 하는 객체를 직접 가져와 스스로 초기화 하는 방법 (서비스 중개자 패턴, 16장)

class Superpower {
	protected:
    	void spawnParticles(ParticleType type, int count) {
        	particleSystem& particles = Locator::getParticles();
            particles.spawn(type, count);
        }
    }
    // 샌드박스 메서드와 그 외 다른 기능들
};

+ Recent posts