패턴명칭
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 패턴을 통해 차원이 다른 구현을 분리함으로써 구현을 효과적으로 할 수 있으며, 구현된 기능을 다양하게 조합할 수 있다.