Chapter 20. Flyweight : 동일한 것을 공유해서 낭비를 없앤다

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

1. 예제 프로그램 - '큰 문자'를 출력하는 프로그램
<BigChar.java>

package ch20.Sample;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

// ‘큰 문자’를 나타내는 클래스
// 파일로부터 큰 문자의 텍스트를 읽어 메모리 상에 로드하고, 
// print 메소드에서 그것을 표시한다.
// 큰 문자는 메모리를 많이 차지하므로, BigChar의 인스턴스를 공유하자.
public class BigChar {
	// 문자의 이름
	private char charname;

	// 큰 문자를 표현하는 문자열
	private String fontdata;

	// 인수로 제공된 문자의 ‘큰 문자’ 버전을 작성한다.
	public BigChar(char charname) {
		this.charname = charname;
		try {
			BufferedReader reader = new BufferedReader(new FileReader("big"+ charname + ".txt"));
			String line;
			StringBuffer buf = new StringBuffer();
			// 파일로부터 한 라인씩 읽어서, “\n”과 함께 buf 에 추가한다.
			while ((line = reader.readLine()) != null) {
				buf.append(line);
				buf.append("\n");
			}
			reader.close();
			this.fontdata = buf.toString();  // 작성된 문자열을 fontdata에 저장함
		} catch (IOException e) {
			this.fontdata = charname + "?";
		}
	}

	// 큰 문자를 표시한다.
	public void print() {
		System.out.print(fontdata);
	}
}

<BigcharFactory.java>

package ch20.Sample;

import java.util.Hashtable;

// BigChar의 인스턴스를 작성하는 공장
// 여기서 인스턴스의 공유가 실현된다.
public class BigCharFactory {
	// 이미 만들어진 BigChar의 인스턴스를 모아서 관리한다.
	private Hashtable pool = new Hashtable();

	// Singleton 패턴을 사용함.
	private static BigCharFactory singleton = new BigCharFactory();

	// 생성자는 private
	private BigCharFactory() {
	}

	// 유일한 하나의 인스턴스를 얻는다.
	public static BigCharFactory getInstance() {
		return singleton;
	}

	// Flyweight 패턴의 중심이 되는 메소드
	// 인수로 제공된 문자에 대응하는 BigChar 인스턴스를 만든다
	public synchronized BigChar getBigChar(char charname) {
		BigChar bc = (BigChar) pool.get("" + charname);
		
		if (bc == null) { // 생성된 BigChar 가 없다면...
			bc = new BigChar(charname); // 여기에서 BigChar의 인스턴스를 생성
			pool.put("" + charname, bc); // pool에 추가한다.
		}
		// 생성된 BigChar 가 있다면, 이것을 반환한다.
		return bc;
	}
}

<BigString.java>

package ch20.Sample;

// BigChar들을 모은 ‘큰 문자열’ 클래스
public class BigString {
	// "큰 문자"의 배열
	private BigChar[] bigchars;

	// 생성자
	// 입력 인자인 문자열에 해당하는 "큰 문자열"을 만든다. 
	public BigString(String string) {
		bigchars = new BigChar[string.length()];
		BigCharFactory factory = BigCharFactory.getInstance();

		// 필드 bigchars 배열의 각 원소는 
		// BigCharFactory로부터 BigChar를 얻어서 참조한다.
		for (int i = 0; i < bigchars.length; i++) {
			bigchars[i] = factory.getBigChar(string.charAt(i));
		}
		
		// 설명: 
		// BigCharFactory은, 
		// 이미 생성된 BigChar인 경우에는 
		// 기존의 BigChar 인스턴스를 반환하므로, 
		// bigchars 배열의 각 원소는 같은 문자에 대해서는 BigChar 객체를 공유한다.
		
		// (참고) 매번 새로운 인스턴스를 생성하는 경우
/*
		for (int i = 0; i < bigchars.length; i++) {
	        bigchars[i] = new BigChar(string.charAt(i));
	    }
*/

	}

	// 표시
	public void print() {
		for (int i = 0; i < bigchars.length; i++) {
			bigchars[i].print();
		}
	}
}

<Main.java>

package ch20.Sample;
public class Main {
	// 명령행 인자로 들어온 문자열을 실인자로 해서, 
	// BigString( ) 객체를 생성한다.
    public static void main(String[] args) {
        if (args.length == 0) {
            System.out.println("Usage: java Main digits");
            System.out.println("Example: java Main 1212123");
            System.exit(0);
        }

        BigString bs = new BigString(args[0]);
        bs.print();
    }
}


2. 연습 문제 1번 + 연습 문제 2번 - BigChar 인스턴스를 공유한 경우와 공유하지 않은 경우의 메모리 소비량을 비교
<BigChar.java>

package ch20.A2;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class BigChar {
     // 문자의 이름
    private char charname;
    //큰 문자를 표현하는 문자열 ('#' '.' '\n'의 열)
    private String fontdata;
    //생성자
    public BigChar(char charname) {
        this.charname = charname;
        try {
            BufferedReader reader = new BufferedReader(
                new FileReader("big" + charname + ".txt")
            );
            String line;
            StringBuffer buf = new StringBuffer();
            while ((line = reader.readLine()) != null) {
                buf.append(line);
                buf.append("\n");
            }
            reader.close();
            this.fontdata = buf.toString();
        } catch (IOException e) {
            this.fontdata = charname + "?";
        }
    }
    // 큰 문자를 표시한다.
    public void print() {
        System.out.print(fontdata);
    }
}

<BigCharFactory.java>

package ch20.A2;
import java.util.Hashtable;

public class BigCharFactory {
    //이미 만들어진 BigChar의 인스턴스를 관리
    private Hashtable pool = new Hashtable();
    //  Singleton 패턴
    private static BigCharFactory singleton = new BigCharFactory();
    // 생성자
    private BigCharFactory() {
    }
    // 유일한 하나의 인스턴스를 얻는다.
    public static BigCharFactory getInstance() {
        return singleton;
    }
    // BigChar의 인스턴스 생성(공유)
    public synchronized BigChar getBigChar(char charname) {
        BigChar bc = (BigChar)pool.get("" + charname);
        if (bc == null) {
            bc = new BigChar(charname); // 여기에서  BigChar의 인스턴스를 생성
            pool.put("" + charname, bc);
        }
        return bc;
    }
}

<BigString.java>

package ch20.A2;
public class BigString {
    //  "큰 문자"의 배열
    private BigChar[] bigchars;
    //  생성자
    public BigString(String string) {
        init_shared(string);
    }
    // 생성자
    public BigString(String string, boolean shared) {
        if (shared) {
            init_shared(string);
        } else {
            init_unshared(string);
        }
    }
    // 공유해서 초기화
    private void init_shared(String string) {
        bigchars = new BigChar[string.length()];
        BigCharFactory factory = BigCharFactory.getInstance();
        for (int i = 0; i < bigchars.length; i++) {
            bigchars[i] = factory.getBigChar(string.charAt(i)); 
        }
    }
    // 공유하지 않고 초기화
    private void init_unshared(String string) {
        bigchars = new BigChar[string.length()];
        for (int i = 0; i < bigchars.length; i++) {
            bigchars[i] = new BigChar(string.charAt(i));    
        }
    }
    //표시
    public void print() {
        for (int i = 0; i < bigchars.length; i++) {
            bigchars[i].print();
        }
    }
}

<Main.java>

package ch20.A2;

public class Main {
    private static BigString[] bsarray = new BigString[1000];
    public static void main(String[] args) {
        System.out.println("공유한 경우:");
        testAllocation(true);
        System.out.println("공유하지 않은 경우:");
        testAllocation(false);
        
        if (args.length == 0) {
            System.out.println("Usage: java Main digits");
            System.out.println("Example: java Main 1212123");
            System.exit(0);
        }
        BigString bs;
        bs = new BigString(args[0], false);     // 공유하지 않는다.
        bs.print();
        bs = new BigString(args[0], true);      // 공유한다.
        bs.print();
    }
    public static void testAllocation(boolean shared) {
        for (int i = 0; i < bsarray.length; i++) {
            bsarray[i] = new BigString("1212123", shared);
        }
        showMemory();
    }
    public static void showMemory() {
        Runtime.getRuntime().gc();
        long used = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
        System.out.println("사용 메모리 = " + used);
    }
}

profile
가보자고

0개의 댓글

관련 채용 정보