1. 예제 프로그램 - 문자열 주위에 장식(-,+,|문자)을 입혀 표시하는 프로그램
<Display.java>
package ch12.Sample;
// 여러 줄로 이루어진 문자열을 표시하기 위한 추상 클래스
public abstract class Display {
public abstract int getColumns(); // 가로의 문자수를 얻는다.
public abstract int getRows(); // 세로의 줄수를 얻는다.
public abstract String getRowText(int row); // row번째의 문자열을 얻는다.
//모든 줄을 화면에 표시하는 메소드
// Template Method 패턴이 적용됨
// 템플릿 메소드: 추상 메소드들을 호출하는 문장들로 이루어진 메소드
public final void show() {
for (int i = 0; i < getRows(); i++) {
System.out.println(getRowText(i));
}
}
}
<StringDisplay.java>
package ch12.Sample;
// 여러 케이크의 중심에 있는 스펀지 케이크에 해당하는 클래스
public class StringDisplay extends Display {
private String string; // 표시할 문자열을 저장함
public StringDisplay(String string) { // 인수로 표시문자열을 지정
this.string = string;
}
public int getColumns() { // 문자수
return string.getBytes().length; // 문자열이 차지하는 바이트 수를 반환함
}
public int getRows() { // 줄수는 1
return 1;
}
// 입력 매개 변수 row가 0일 때만 string 필드를 반환한다.
public String getRowText(int row) {
if (row == 0) {
return string;
} else {
return null;
}
}
}
<Border.java>
package ch12.Sample;
// ‘장식’을 나타내는 추상 클래스
// StringDisply와 Border는 모두 Display의 하위 클래스이다.
// => StringDisplay(내용물)가 Border(장식자)를 동일시한다.
// => 즉, 장식자도 또다른 장식자의 내용물이 될 수 있다.
public abstract class Border extends Display {
protected Display display; // 장식이 감싸고 있는 "내용물"을 가리킨다.
// StringDisplay 뿐 만 아니라 Border 도 참조할 수 있다.
// 이유: Border도 Display의 하위 클래스이므로
protected Border(Display display) { // 인스턴스 생성시에 "내용물"을 인수로 지정
this.display = display;
}
}
<SideBorder.java>
package ch12.Sample;
// 구체적인 장식의 일종
// 문자열 좌우에 정해진 문자(BorderChar)로 장식한다.
public class SideBorder extends Border {
private char borderChar; // 장식이 되는 문자
// 생성자에서, 내용물(display)과 장식 문자(ch)가 지정됨
public SideBorder(Display display, char ch) {
super(display);
this.borderChar = ch;
}
// 내용물의 문자 수에 2(내용물의 양쪽에 장식 문자분)를 더한다.
public int getColumns() {
return 1 + display.getColumns() + 1;
}
// 줄수는 내용물의 줄수와 같으므로, 내용물의 getRows( )를 호출한다.
public int getRows() {
return display.getRows();
}
// 지정한 줄의 내용물의 Text 양쪽에 장식 문자를 연결하여 반환한다.
public String getRowText(int row) {
return borderChar + display.getRowText(row) + borderChar;
}
}
<FullBorder.java>
package ch12.Sample;
// 상하좌우에 장식을 다는 클래스
// SideBorder와 달리, 장식할 문자가 미리 고정되어 있다.
public class FullBorder extends Border {
public FullBorder(Display display) {
super(display);
}
// 문자수는 내용물의 양쪽에 좌우의 장식 문자분을 더한 것
public int getColumns() {
return 1 + display.getColumns() + 1;
}
// 줄수는 내용물의 줄수에 상하의 장식문자분을 더한 것
public int getRows() {
return 1 + display.getRows() + 1;
}
// 지정한 줄의 내용을 반환함
public String getRowText(int row) {
if (row == 0) { // 장식의 상단인 경우
return "+" + makeLine('-', display.getColumns()) + "+"; // "+---------------------+" 를 만든다.
} else if (row == display.getRows() + 1) { // 장식의 하단인 경우
return "+" + makeLine('-', display.getColumns()) + "+"; // "+---------------------+" 를 만든다.
} else { // 그 밖의 경우
return "|" + display.getRowText(row - 1) + "|";//1빼는것이 중요
}
}
// ch를 count 갯수 만큼 연속해서 문자열로 만드는 메소드
private String makeLine(char ch, int count) {
StringBuffer buf = new StringBuffer();
for (int i = 0; i < count; i++) {
buf.append(ch);
}
return buf.toString();
}
}
<Main.java>
package ch12.Sample;
public class Main {
public static void main(String[] args) {
// StringDisplay를 테스트
Display d1 = new StringDisplay("hello");
/*
System.out.println(d1.getRows());
System.out.println(d1.getColumns());
d1.show();
*/
//장식자 1
Display d2 = new SideBorder(d1, '*');
d2.show();
Display d3 = new SideBorder(d2, '/');
d3.show();
Display d4 = new SideBorder(d3, '#');
d4.show();
//장식자2
Display d5 = new FullBorder(d1);
d5.show();
Display d6 = new FullBorder(d5);
d6.show();
Display d7 = new SideBorder(d6, '*');
d7.show();
System.out.println();
Display b1 = new StringDisplay("Hello, world."); // ‘Hello, world.’를 장식하지 않고 표시한 것
Display b2 = new SideBorder(b1, '#'); // b1에 대해 ‘#’ 문자로 좌우에 장식한 것
Display b3 = new FullBorder(b2); // b2에 대해 전체 장식을 한 것
b1.show();
b2.show();
b3.show();
// ‘안녕하세요’에 여려 겹 장식을 한다.
Display b4 =
new SideBorder(
new FullBorder(
new FullBorder(
new SideBorder(
new FullBorder(
new StringDisplay("안녕하세요")
),
'*'
)
)
),
'/'
);
b4.show();
if(b1 instanceof StringDisplay)
System.out.println("b1 is instanceof StringDisplay");
else if(b1 instanceof SideBorder)
System.out.println("b1 is instanceof SideBorder");
if(b1 instanceof Display)
System.out.println("b1 is instanceof Display");
}
}