design pattern #9 Structural pattern - Decorator

  • 이름은 낯설지만, wrapper class 형태로 씌우는것을 말한다
  • wrapper 로 감싸고, 추가적인 기능을 덧붙인다
  • 추가적인 기능을 덧붙이는데, 상속이 편히 쓸 수 있는 방법인데, 이와같은 wrapper 형식을 통하면, reference 를 가지고 있으며 추가 기능을 붙이고, 필요한 일을 delegate 시킬 수 있다.

  • File 을 Decorate 한다고 치자.
  • interface 로 DataSource 를 만들고,
  • DataSource 를 implement 한 FileDataSource 가 있다.
  • DataSource Decorator  (DataSource Wrapper 라고 이해했다)역시 DataSource 를 implement 한다.
  • Decorator 안에 wrappee 가 있고, 이게 datasource 가 된다.
  • DataSourceDecorator 를 보면, DataSource 를 implement 했는데, wrappee 도 type이 DataSource 이다.
  • 그리고 이 wrapper 를 상속하여 구체 decorator 를 만든게 EncryptDecorator, CompressDecorator 다.
  • 만일 이렇게 하지 않고 상속 한다면, FileDataSource 를 상속 받아, EcryptFileDataSource, CompressFileDataSource 이런식으로 했겠지. 
  • wrapper의 또 장점은,  예제에서처럼,  wrapper 를 한번 더 다른 wrapper 로 감싸는 식으로 할수 있다. 

public interface DataSource {
void writeData(String data);

String readData();
}

public class FileDataSource implements DataSource {
private String name;

public FileDataSource(String name) {
this.name = name;
}

@Override
public void writeData(String data) {
File file = new File(name);
try (OutputStream fos = new FileOutputStream(file)) {
fos.write(data.getBytes(), 0, data.length());
} catch (IOException ex) {
System.out.println(ex.getMessage());
}
}

@Override
public String readData() {
char[] buffer = null;
File file = new File(name);
try (FileReader reader = new FileReader(file)) {
buffer = new char[(int) file.length()];
reader.read(buffer);
} catch (IOException ex) {
System.out.println(ex.getMessage());
}
return new String(buffer);
}
}

public class DataSourceDecorator implements DataSource {
private DataSource wrappee;

DataSourceDecorator(DataSource source) {
this.wrappee = source;
}

@Override
public void writeData(String data) {
wrappee.writeData(data);
}

@Override
public String readData() {
return wrappee.readData();
}
}

public class EncryptionDecorator extends DataSourceDecorator {

public EncryptionDecorator(DataSource source) {
super(source);
}

@Override
public void writeData(String data) {
super.writeData(encode(data));
}

@Override
public String readData() {
return decode(super.readData());
}

private String encode(String data) {
byte[] result = data.getBytes();
for (int i = 0; i < result.length; i++) {
result[i] += (byte) 1;
}
return Base64.getEncoder().encodeToString(result);
}

private String decode(String data) {
byte[] result = Base64.getDecoder().decode(data);
for (int i = 0; i < result.length; i++) {
result[i] -= (byte) 1;
}
return new String(result);
}
}

public class CompressionDecorator extends DataSourceDecorator {
private int compLevel = 6;

public CompressionDecorator(DataSource source) {
super(source);
}

public int getCompressionLevel() {
return compLevel;
}

public void setCompressionLevel(int value) {
compLevel = value;
}

@Override
public void writeData(String data) {
super.writeData(compress(data));
}

@Override
public String readData() {
return decompress(super.readData());
}

private String compress(String stringData) {
byte[] data = stringData.getBytes();
try {
ByteArrayOutputStream bout = new ByteArrayOutputStream(512);
DeflaterOutputStream dos = new DeflaterOutputStream(bout, new Deflater(compLevel));
dos.write(data);
dos.close();
bout.close();
return Base64.getEncoder().encodeToString(bout.toByteArray());
} catch (IOException ex) {
return null;
}
}

private String decompress(String stringData) {
byte[] data = Base64.getDecoder().decode(stringData);
try {
InputStream in = new ByteArrayInputStream(data);
InflaterInputStream iin = new InflaterInputStream(in);
ByteArrayOutputStream bout = new ByteArrayOutputStream(512);
int b;
while ((b = iin.read()) != -1) {
bout.write(b);
}
in.close();
iin.close();
bout.close();
return new String(bout.toByteArray());
} catch (IOException ex) {
return null;
}
}
}

public static void main(String[] args) {
String salaryRecords = "Name,Salary\nJohn Smith,100000\nSteven Jobs,912000";
DataSourceDecorator encoded = new CompressionDecorator(
new EncryptionDecorator(
new FileDataSource("out/OutputDemo.txt")));
encoded.writeData(salaryRecords);
DataSource plain = new FileDataSource("out/OutputDemo.txt");

System.out.println("- Input ----------------");
System.out.println(salaryRecords);
System.out.println("- Encoded --------------");
System.out.println(plain.readData());
System.out.println("- Decoded --------------");
System.out.println(encoded.readData());
}

Comments

Popular posts from this blog

삼성전자 무선사업부 퇴사 후기

코드리뷰에 대하여

개발자 커리어로 해외 취업, 독일 이직 프로세스