Toggle menu
Toggle personal menu
Not logged in
Your IP address will be publicly visible if you make any edits.

DelegationPattern

From ZeroWiki

클래스에 대해 기능을 확장하는 두가지 방법중 하나이다. 하나는 상속이고 하나는 위임(Delegation) 이다. 상속을 하지 않아도 해당 클래스의 기능을 확장시킬 수 있는 방법이 된다.

또한, 클래스 하나가 방대해질때, 적절하게 그 클래스의 책임을 다른 클래스들에게 위임해주는 것은 Refactoring 의 방법이 된다.

ObjectOrientedProgramming 을 할때 자주 쓰이는 코딩 스타일. 아마 사람들이 무의식중에 자주 쓸 것이다.

example) 예전에 VonNeumannAirport 을 JuNe 과 1002 가 Pair 하던중 JuNe 이 작성했던 Refactoring 으로서의 Delegation.

public class Airport {
	private int _traffic;
	private int [] _arrivalGate;
	private int [] _departureGate;
	private PassengerSet psg;
		
	public int getTraffic() {
		ListIterator iter = psg.passengers.listIterator();
		int [] passenger;
		
		while (iter.hasNext()) {
			passenger = (int [])iter.next();
			movePassenger(passenger[0], 
						passenger[1],
						passenger[2]);
		}
		
		return _traffic;
	}	
	
	public void setArrivalGates(int [] aCity) {
		_arrivalGate = aCity;
	}
	public void setDepartureGates(int [] aCity) {
		_departureGate = aCity;
	}
	
	public int [] getArrivalGates() {
		return _arrivalGate;
	}
	
	public int [] getDepartureGates() {
		return _departureGate;
	}
	public int getDistance(int fromCity, int toCity){
		int distance=java.lang.Math.abs(_getArrivalCityGate(fromCity)
		                             -_getDepartureCityGate(toCity))+1;
		return distance;
	}	

	private void movePassenger(int fromCity, int toCity, int aNumber) {
		_traffic+=getDistance(fromCity,toCity)*aNumber;
	}
	public void setPassengers(PassengerSet psg) {
		this.psg=psg;
	}
}

여기까지는 Airport 이다. 하지만 VonNeumannAirport 문제에서도 보듯, 실제 Input 에 대해서 Configuration 은 여러 Set 이 나온다.

이 기능을 추가하기 위해 일단 Airport Code 를 Refactoring 하기로 했다. 이를 위해 Airport 의 기능중 Configuration 과 관련된 기능에 대해 Configuration 을 Extract 하고, 내부적으로는 Delegation 함으로서 외부적으로 보이는 기능에 대해서는 일관성을 유지한다. (Test Code 가 일종의 Guard 역할을 했었음)

import java.util.ListIterator;

class Configuration {
	private int [] _arrivalGate;
	private int [] _departureGate;
	private int id;
	
	public void setArrivalGates(int [] aCity) {
		_arrivalGate=aCity;
	}
	public void setDepartureGates(int [] aCity) {
		_departureGate=aCity;	
	}
	
	public int [] getArrivalGates() {
		return _arrivalGate;
	}
	
	public int [] getDepartureGates() {
		return _departureGate;	
	}
	public int getDistance(int fromCity, int toCity){
		int distance=java.lang.Math.abs(_getArrivalCityGate(fromCity)
		                             -_getDepartureCityGate(toCity))+1;
		return distance;
	}	
	public int _findInIntArray(int anInt,int [] anArray) {
		for (int i=0;i<anArray.length;i++) {
			if (anArray[i] == anInt) return i+1;
		}
		return -1;
	}
			
	public int _getArrivalCityGate(int aCity) {
		return _findInIntArray(aCity,getArrivalGates());
	}
	
	public int _getDepartureCityGate(int aCity) {
		return _findInIntArray(aCity,getDepartureGates());
	}
	
	public int getId() {
		return id;
	}
	
	public void setId(int anId) {
		id=anId;
	}
	
}

public class Airport {
	private int _traffic;
	private int [] _arrivalGate;
	private int [] _departureGate;
	private PassengerSet psg;
	private Configuration conf=new Configuration();
		
	public int getTraffic() {
		ListIterator iter = psg.passengers.listIterator();
		int [] passenger;
		
		while (iter.hasNext()) {
			passenger = (int [])iter.next();
			movePassenger(passenger[0], 
						passenger[1],
						passenger[2]);
		}
		
		return _traffic;
	}	
	
	public void setArrivalGates(int [] aCity) {
		conf.setArrivalGates(aCity);
	}
	public void setDepartureGates(int [] aCity) {
		conf.setDepartureGates(aCity);
	}
	
	public int [] getArrivalGates() {
		return conf.getArrivalGates();
	}
	
	public int [] getDepartureGates() {
		return conf.getDepartureGates();
	}
	public int getDistance(int fromCity, int toCity){
		return conf.getDistance(fromCity,toCity);
	}	

	private void movePassenger(int fromCity, int toCity, int aNumber) {
		_traffic+=getDistance(fromCity,toCity)*aNumber;
	}
	public void setPassengers(PassengerSet psg) {
		this.psg=psg;
	}
}

DelegationPattern을 쓸 때 중요한 점은, DelegationPattern을 사용하는 클래스의 클라이언트는 그 클래스가 Delegation을 쓰는지 안쓰는지 몰라야 한다는 것이다. 즉, 우리에게 있어 DelegationPattern이 사용된 클래스는 여느 클래스와 동일하게 인식되고 사용되어져야 한다. 게을러서 남에게 자신의 숙제를 위임하는 학생은 절대 남들에게 그 사실을 노출해선 안된다.

ResponsibilityDrivenDesign , Refactoring, DelegationPattern 을 꾸준히 지켜주면 좋은 코드가 나올 수 있다. (DesignPattern 이 유도되어짐)

See Also Seminar:DelegationPattern


전에 SE 수업중에 컴포넌트모델의 필요성을 이야기하던중 '상속으로의 재사용이 어렵기 때문에' 이야기를 하셨는데, 왜 대안 중 하나로서의 Delegation 에 대한 언급이 전혀 없으셨는지 모르겠다. Delegation 만 잘 이해해도 준 컴포넌트 스타일의 모듈화 프로그래밍을 잘 진행할 수 있고, 사람들 간의 작업분담도 잘 이끌어 낼 수 있을건데.. --[1002]


패턴분류