글
Fluent Interface 적용 사례
2006/소프트웨어 설계
2006/09/19 02:13
2006/01/11 (수) 23:50 에 작성된 글을 엠파스 블로그에서 옮겨옵니다.
그래서, 이를 래핑하는 과정에서 Fluent Interface를 적용했습니다. 해당 제품의 API는 객체의 데이터를 Dataset 이라는 일종의 컨테이너 클래스에 담아서 전송하게 되어 있었습니다. 이를 자동으로 생성하는 코드를 만도는 것은 적절하지 못한 상황이었습니다. 미봉책이나마 개발자들의 편의성을 높여야 했습니다. 그러다보니 '정형화 된 속성 값을 설정하고, 값을 담는 일' 이기에 Fluent Interface를 적용할만 했던 것이죠.
위와 같은 설정을 보면 속성이 많아지고, 컴포지트(composite) 형태의 객체를 평면화(객체지향 아닌 기술과 데이터를 주고 받을 때 포함하는 객체까지 전부 끌어내는 현상을 제가 부르는 이름..ㅡㅡ;)하면.. 위와 같은 지루한 코드가 상당히 길게 작성됩니다. 실제로는 이런 류의 클래스마다 값을 설정하는데 수 십줄이 필요하게 됩니다.
대개 설정에 관여되는 Setter 유형의 메소드는 반환값이 void 이거나 성공/실패 여부를 반영하기 쉽상인데, 그런 방식이 아니라 생성된 객체를 다시 반환해주면 릴레이로 생성할 수 있죠. 계주를 떠올리면 딱이네요.. ^^
위와 같이 더 축약하실 수도 있죠.
Martin Fowler 의 글, Fluent Interface를 읽고 번역할 즈음에 수행하던 프로젝트에서 라이브러리를 구현하게 되었습니다. 용도가 적절하다 싶어 적용해보고 싶은 마음이 들더군요. 적용 대상으로 선정한 부분은 자바 기반의 웹 프로그램과 특정 라이브러리를 사용하는 제품 사이의 데이터 형식 변환이었습니다. 해당 제품이 제공하는 라이브러리 API 를 써야 하는데 편의성에 약간의 문제가 있었죠.
그래서, 이를 래핑하는 과정에서 Fluent Interface를 적용했습니다. 해당 제품의 API는 객체의 데이터를 Dataset 이라는 일종의 컨테이너 클래스에 담아서 전송하게 되어 있었습니다. 이를 자동으로 생성하는 코드를 만도는 것은 적절하지 못한 상황이었습니다. 미봉책이나마 개발자들의 편의성을 높여야 했습니다. 그러다보니 '정형화 된 속성 값을 설정하고, 값을 담는 일' 이기에 Fluent Interface를 적용할만 했던 것이죠.
Dataset dsCustomer= new Dataset("dsCustomer");
dsCustomer.addColumn("id", ...);
dsCustomer.addColumn("name", ... );
dsCustomer.addColumn("address", ... );
dsCustomer.addColumn("customerTypeId", ... );
dsCustomer.addColumn("customerTypeDescription", ... );
dsCustomer.addColumn("description", ... );
dsCustomer.addColumn("groupId", ... );
dsCustomer.addColumn("groupName", ... );
dsCustomer.addColumn("id", ...);
dsCustomer.addColumn("name", ... );
dsCustomer.addColumn("address", ... );
dsCustomer.addColumn("customerTypeId", ... );
dsCustomer.addColumn("customerTypeDescription", ... );
dsCustomer.addColumn("description", ... );
dsCustomer.addColumn("groupId", ... );
dsCustomer.addColumn("groupName", ... );
위와 같은 설정을 보면 속성이 많아지고, 컴포지트(composite) 형태의 객체를 평면화(객체지향 아닌 기술과 데이터를 주고 받을 때 포함하는 객체까지 전부 끌어내는 현상을 제가 부르는 이름..ㅡㅡ;)하면.. 위와 같은 지루한 코드가 상당히 길게 작성됩니다. 실제로는 이런 류의 클래스마다 값을 설정하는데 수 십줄이 필요하게 됩니다.
Dataset dsCustomer= new Dataset("dsCustomer")
.addColumn("id", ...)
.addColumn("name", ... )
.addColumn("address", ... )
.addColumn("customerTypeId", ... )
.addColumn("customerTypeDescription", ... )
.addColumn("description", ... )
.addColumn("groupId", ... )
.addColumn("groupName", ... );
.addColumn("id", ...)
.addColumn("name", ... )
.addColumn("address", ... )
.addColumn("customerTypeId", ... )
.addColumn("customerTypeDescription", ... )
.addColumn("description", ... )
.addColumn("groupId", ... )
.addColumn("groupName", ... );
대개 설정에 관여되는 Setter 유형의 메소드는 반환값이 void 이거나 성공/실패 여부를 반영하기 쉽상인데, 그런 방식이 아니라 생성된 객체를 다시 반환해주면 릴레이로 생성할 수 있죠. 계주를 떠올리면 딱이네요.. ^^
만일, addColumn 말고도 다른 것들이 많이 설정되야 하는 것이 아니라면 메소드를 더 축약할 수도 있겠죠. Dataset 에는 컬럼만 추가된다거나 하는 상황이라면..
Dataset dsCustomer= new Dataset("dsCustomer")
.with("id", ...).with("name", ... ).with("address", ... )
.with("customerTypeId", ... ).with("customerTypeDescription", ... )
.with("description", ... ).with("groupId", ... ).with("groupName", ... );
.with("id", ...).with("name", ... ).with("address", ... )
.with("customerTypeId", ... ).with("customerTypeDescription", ... )
.with("description", ... ).with("groupId", ... ).with("groupName", ... );
위와 같이 더 축약하실 수도 있죠.
그러나, 이러한 방식이 도움이 되는 경우는 한정되어 있습니다.
- 자동화가 어려운 상황에서 빈번한 설정이 요구되는 작업을 간편하게 하고자 할 때 유용함.
- 설정하는 데이터가 많으면서, 유형은 단순할 수록 효과가 커짐