참고 URL
https://webcourse.cs.technion.ac.il/236700/Spring2013/ho/WCFiles/pp.pdf
일반적으로 프로퍼티라고 하면 "특성" 정도로 번역할 수 있다. 특성이란 어떤 대상이 동 종의 다른 대상과 다른점을 말한다. 이것을 소프트웨어 용어로 표현하자면 대상이란 객체를 말하고, 특성이란 변수라고 이야기 할 수 있다. 그리고 변수는 이름과 값으로 나타내어 질 수 있다. 이렇게 이름과 값으로 나타내어 질 수 있는 것들을 클래스에 직접 선언하지 않고, HashMap과 같은 Collection에 저장하여 둠으로써 프로퍼티의 동적인 변화에 대응할 수 있도록 하는 것이 Property List 패턴이다.
자료에서는 다음과 같은 이름으로도 불릴 수 있다고 한다.
- Prototype
- Property List
- Properties Object
- Adaptive Object Model(이것은 이 프로퍼티 패턴을 확장한 패턴이다. 동일한 것으로 취급되기는 어렵다)
Property List 패턴의 클래스 다이어그램
Property List 패턴은 PropList 객체를 중심으로 구성된다. PropList 객체는 동일한 타입을 parent 참조 변수를 통해 가지고 있는 복합 객체이다. 이 다이어그램에서는 PropList와 그 인터페이스인 IPropList를 구분시켜 두었다. 이는 parent에 대한 null 체크 등을 방지하기 위해서 parent의 기본 참조를 Null 객체인 NullPropList로 가지고 가기 위해서이다. 이 패턴에서 구조적으로 중요한 부분은 PropList를 parent로 가지고 있다는 점이고, 사실 API의 이해에 더 집중해야 하는 패턴이다.
Property List 패턴의 구현
interface IPropList{
public Object get(String key);
public void put(String key, Object value);
public boolean has(String key);
public void remove(String key);
public Collection<String> keys();
public IPropList parent();
}
class NullPropList implements IPropList{
public Object get(String key){return null;}
public void put(String key, Object value){/* not use */}
public boolean has(String key){return false;}
public void remove(String key){/* not use */}
public Collection<String> keys(){return Collections.emptySet();}
public IPropList parent(){return null;}
}
class PropList implements IPropList{
private IPropList parent = new NullPropList();
private Map<String, Object> map = new HashMap<String, Object>();
public PropList(IPropList parent){
if(parent != null) this.parent = parent;
}
public Object get(String key){
if(map.containsKey(key)) return map.get(key);
return parent.get(key);
}
public void put(String key, Object value){
map.put(key, value);
}
public boolean has(String key) {
return map.containsKey(key) || parent.has(key);
}
public void remove(String key){
map.remove(key);
}
public Collection<String> keys(){
List<String> result = new ArrayList<String>();
result.addAll(map.keySet());
result.addAll(parent.keys());
return result;
}
public IPropList parent(){ return parent; }
}
이 구현은 참고 URL 자료에 나와 있는 코드를 거의 그대로 사용한 것이다. 다만, parent에 대한 설정이 생성 즉시 이루어지고 있고, 별도로 parent에 대한 의존성 주입 메소드가 없기 때문에 사실상 일부러 null을 넣지 않는 한 null이 발생할 수는 없다. 따라서 Null 객체 패턴을 적용하여 null을 체크하는 부분들을 모두 없앰으로써 전체 소스의 간결함을 유지하도록 하였다.
이 패턴의 동작은 PropList 객체를 생성하면서 시작된다. 생성자를 통해 객체를 생성할 때 인자로 IPropList 타입인 parent를 넣어 주게 되어 있다. 이는 어떤 프로퍼티 리스트가 다른 프로퍼티 리스트들을 메타 데이터로 가지고 있을 경우를 위한 것이다. 예를 들어 아이폰의 특성을 나타낸다면, 제품명은 모두 다 같은 아이폰이다. 개별 제품들의 시리얼 번호는 각각 다를 것이다. 그렇다면 모두 같은 값을 나타내는 제품명이라는 프로퍼티를 모든 개별 제품들에 넣게 되면 메모리 소모가 많아지게 될 것이다. 따라서 이를 방지하기 위한 목적으로 parent를 별도로 둔다.
이 parent는 필요에 따라서는 계층화 될 수도 있다. 즉 parent가 또 그 상위에 메타 프로퍼티들을 가지도록 구성할 수도 있다.
PropList의 생성 이후 동작은 대부분 프로퍼티의 삽입 / 조회 / 삭제에 관한 것들이다. 일반적인 객체들의 경우 변수에 대한 조회, 변경을 통해서 동작하듯이 Property List 패턴도 그런 목적에 맞도록 이들 연산을 지원한다.
자료에서는 이 패턴이 만들어지게 된 배경에 대해 이렇게 이야기 하고 있다.
- No SQL 데이터 베이스를 이용한 어플리케이션 구현
관계형 DB의 확장성 문제를 해결하기 위해 No SQL 데이터베이스들을 이용할 경우 key - attribute - value 형식의 테이블을 사용하게 되는데 이런 경우 데이터 베이스와의 연동성이 좋다.
- 프로퍼티 리스트의 유연성이 좋다
- 비즈니스 로직이 프로퍼티의 특정한 값들에 대해서 그다지 관심이 없는 경우에 좋다
사용에 있어서 주의할 점이 있다면 다음과 같다.
- 아무래도 객체를 직접 구현하는 것에 비해서 프로퍼티의 조회는 좀 더 구현이 복잡하다. 만약 이 패턴을 사용하여 복잡한 계산 로직을 구현한다면 문제가 될 것이다. 비즈니스 로직은 매우 단순하면서 다루어야 할 객체의 종류가 많은 어플리케이션에 매우 적합한 패턴이다.
- 프로퍼티란 마치 변수와 같은 것이다. 이 패턴은 객체의 생성 없이 객체를 흉내내려는 패턴이라 할 수 있다. 이를 통해 유연성을 얻을 수는 있지만 캡슐화의 장점은 포기해야 한다.
- 특히 value에 해당하는 객체의 관리에 신중해야 한다. 접근 관리가 잘못되면 전역 변수처럼 사용되버릴 수도 있다.
이 패턴에 맞는 응용 분야는 다음과 같다.
- 동일한 프로토콜을 사용하는 여러 장치들의 데이터를 수집해야 하는 센서 관련 소프트웨어
- 다양한 제품군과 제품들을 취급하는 경우
- 사용자가 필요에 따라서 새로운 제품을 계속 추가해야 하는 경우
'5.디자인패턴' 카테고리의 다른 글
Adaptive Object Model(AOM) 패턴 및 그 구현 (0) | 2016.10.01 |
---|---|
Actor Model 패턴의 구현(Java) (0) | 2016.09.30 |
Mediator 패턴 (0) | 2016.09.18 |
Facade 패턴 (0) | 2016.09.18 |
Command 패턴 (0) | 2016.09.18 |