패턴명칭
Bridge
필요한 상황
어떤 처리에 대한 큰 로직을 상황에 따라 다르게 정의해 실행해야한다. 이와 동시에 해당 로직을 구성하는 세부 항목에 대한 처리들 역시 다르게 정의하고자할때 사용할 수 있는 패턴이다. 즉, 구현의 차원이 2개 이상일때 이를 효과적으로 분리할 수 있는 패턴이다.
예제 코드
위의 예제는 Article 클래스에 정의된 데이터를 화면에 출력할때, 출력에 대한 구현을 Bridge 패턴을 이용해 구현하도록 설계한 클래스다이어그램이다. 먼저 Article 클래스는 다음과 같다.
package tstThread;
import java.util.ArrayList;
public class Article {
private String title;
private ArrayList<String> content;
private String footer;
public Article(String title, ArrayList<String> content, String footer) {
this.title = title;
this.content = content;
this.footer = footer;
}
public String getTitle() {
return title;
}
public ArrayList<String> getContent() {
return content;
}
public String getFooter() {
return this.footer;
}
}
제목과 내용 그리고 꽁지글이 각각 title, content, footer 필드에 저장된다. 이 세개를 출력하는 방식은 IDisplay 인터페이스로 정의되며 다음과 같다.
package tstThread;
public interface IDisplay {
void title(Article article);
void content(Article article);
void footer(Article article);
}
이 인터페이스를 구현하는 클래스는 모두 3개로 먼저 SimpleDisplay는 다음과 같다.
package tstThread;
import java.util.ArrayList;
public class SimpleDisplay implements IDisplay {
@Override
public void title(Article article) {
System.out.println(article.getTitle());
}
@Override
public void content(Article article) {
ArrayList<String> content = article.getContent();
int cntLines = content.size();
for(int i=0; i<cntLines; i++) {
System.out.println(content.get(i));
}
}
@Override
public void footer(Article article) {
System.out.println(article.getFooter());
}
}
ContentReverseDisplay 클래스는 Article의 content를 구성하는 문자열 요소를 역순으로 출력하며 다음과 같다.
package tstThread;
import java.util.ArrayList;
public class ContentReverseDisplay extends SimpleDisplay {
@Override
public void content(Article article) {
ArrayList<String> content = article.getContent();
for(int i=content.size()-1; i>=0; i--) {
System.out.println(content.get(i));
}
}
}
ContentVerticalDisplay 클래스는 Article의 content를 세로방향으로 출력하며 다음과 같다.
package tstThread;
import java.util.ArrayList;
public class ContentVerticalDisplay extends SimpleDisplay {
@Override
public void content(Article article) {
ArrayList<String> content = article.getContent();
int maxChars = 0;
int cntLines = content.size();
for(int i=0; i<cntLines; i++) {
int len = content.get(i).length();
if(len > maxChars) maxChars = len;
}
for(int iCh=0; iCh<maxChars; iCh++) {
for(int iLine=0; iLine<cntLines; iLine++) {
String line = content.get(iLine);
if(line.length() > iCh) {
System.out.print(line.charAt(iCh) + " ");
} else {
System.out.print(" ");
}
}
System.out.println();
}
}
}
IDisplay를 구현하는 SimpleDisplay, ContentReverseDisplay, ContentVerticalDisplay는 Article을 구성하는 title, content, footer 필드를 각각 어떻게 출력할지를 결정하는 구현에 대한 차원이다. 이제 이 IDisplay를 이용해 Article을 실제로 화면에 출력하는 클래스인 User는 다음과 같다.
package tstThread;
public class User {
protected Article article;
public User(Article article) {
this.article = article;
}
public void print(IDisplay display) {
display.title(article);
display.content(article);
display.footer(article);
}
}
print 매서드를 통해 Article 객체를 IDisplay 인터페이스를 통해 출력하고 있는데, 출력하는 순서는 title, content, footer이다. 그런데 또 다른 요구사항으로 footer, content, title라는 순서로 출력하는 기능을 처리하기 위해 User를 상속받아 ReverseUser 클래스를 정의하며 다음과 같다.
package tstThread;
public class ReverseUser extends User {
public ReverseUser(Article article) {
super(article);
}
public void print(IDisplay display) {
display.footer(article);
display.content(article);
display.title(article);
}
}
User와 ReverseUser는 Article을 구성하는 요소를 어떻게 조립할지를 결정하는 구현에 대한 차원이다. 이제 지금까지 정의한 클래스를 사용하는 코드는 다음과 같다.
package tstThread;
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
String title = "GIS, powerful tool";
ArrayList<String> content = new ArrayList<String>();
content.add("GIS is a geographic information system.");
content.add("It is base on real spatial data.");
content.add("It provides analyzing spatial data");
String footer = "2020.10.08, written by Dip2K";
Article article = new Article(title, content, footer);
System.out.println("[CASE-1]");
User case1 = new User(article);
case1.print(new SimpleDisplay());
System.out.println();
System.out.println("[CASE-2]");
User case2 = new ReverseUser(article);
case2.print(new SimpleDisplay());
System.out.println();
System.out.println("[CASE-3]");
User case3 = new ReverseUser(article);
case3.print(new ContentReverseDisplay());
System.out.println();
System.out.println("[CASE-4]");
User case4 = new User(article);
case4.print(new ContentVerticalDisplay());
System.out.println();
}
}
실행 결과는 다음과 같다.
[CASE-1]
GIS, powerful tool
GIS is a geographic information system.
It is base on real spatial data.
It provides analyzing spatial data
2020.10.08, written by Dip2K
[CASE-2]
2020.10.08, written by Dip2K
GIS is a geographic information system.
It is base on real spatial data.
It provides analyzing spatial data
GIS, powerful tool
[CASE-3]
2020.10.08, written by Dip2K
It provides analyzing spatial data
It is base on real spatial data.
GIS is a geographic information system.
GIS, powerful tool
[CASE-4]
2020.10.08, written by Dip2K
G I I
I t t
S
i p
i s r
s o
b v
a a i
s d
g e e
e s
o o
g n a
r n
a r a
p e l
h a y
i l z
c i
s n
i p g
n a
f t s
o i p
r a a
m l t
a i
t d a
i a l
o t
n a d
. a
s t
y a
s
t
e
m
.
GIS, powerful tool
Bridge 패턴을 통해 차원이 다른 구현을 분리함으로써 구현을 효과적으로 할 수 있으며, 구현된 기능을 다양하게 조합할 수 있다.
이 글은 소프트웨어 설계의 기반이 되는 GoF의 디자인패턴에 대한 강의자료입니다. 완전한 실습을 위해 이 글에서 소개하는 클래스 다이어그램과 예제 코드는 완전하게 실행되도록 제공되지만, 상대적으로 예제 코드와 관련된 설명이 함축적으로 제공되고 있습니다. 이 글에 대해 궁금한 점이 있으면 댓글을 통해 남겨주시기 바랍니다.