Chapter 12. Decorator : 장식과 내용물의 동일시

sua·2022년 4월 9일
0
post-thumbnail

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");
	}

}

profile
가보자고

0개의 댓글

관련 채용 정보