코딩 기록들
스프링 입문 2.3 옵저버(Observer), 파사드(facade), 전략(strategy) 패턴 본문
옵저버(Observer) 패턴
- 관찰자패턴
- 스윙, 자바의GUI프로그래밍, 안드로이드 프로그래밍 시 이벤트리스너가 예시(이벤트리스너를 통해 전달)
- 변화가 일어났을때관찰(관찰에 변화가생기면) 미리 등록된 다른클래스에 통보해주는 패턴을 구현한것
public class Main {
public static void main(String[] args) {
Button button = new Button("버튼");
//익명으로 전달받음
button.addListener(new IButtonListener() {
public void clickEvent(String event){
System.out.println(event);
}
});
button.click('메시지 전달 : click 1');
button.click('메시지 전달 : click 2');
button.click('메시지 전달 : click 3');
}
}
public interface IButtonListener {
void clickEvent(String event);
}
public class Button {
private String name;
private IButtonListener buttonListener;
public Button(String name){
this.name = name;
}
public void click(String message){
buttonListener.clickEvent(message );
}
public void addListener(IButtonListener buttonListener){
this.buttonListener = buttonListener;
}
}
파사트 패턴
- 건물의 앞쪽 정면 이라는 뜻. 건물의 뒤쪽에는 뭐가있는지 모르는 상태
- 여러 객체와 실제 사용하는 서브객체 사이에 복잡한 의존관계가 있을때, 중간에 facade라는 객체를 두고, 여기서 제공하는 인터페이스만을 활용하여 기능을 사용하는 방식 (여러개 객체를 합쳐 특정 기능 만들때 사용)
- 자신이 가지고있는 각 클래스의 기능을 명확히 알아야 함
public class Reader {
private String fileName;
public Reader(String fileName){
this.fileName = fileName;
}
public void fileConnect(){
String msg = String.format("Reader %s 로 연결합니다.", fileName);
System.out.println(msg);
}
public void fileRead(){
String msg = String.format("Reader %s 의 내용을 읽어옵니다.", fileName);
System.out.println(msg);
}
public void fileDisconnect(){
String msg = String.format("Reader %s 로 연결 종료 합니다.", fileName);
System.out.println(msg);
}
}
public class Writer {
private String fileName;
public Writer(String fileName){
this.fileName = fileName;
}
public void fileConnect(){ // 생성, 이어쓰기
String msg = String.format("Writer %s 로 연결합니다.", fileName);
System.out.println(msg);
}
public void write(){
String msg = String.format("Writer %s 로 파일쓰기를 합니다.", fileName);
System.out.println(msg);
}
public void fileDisconnect(){
String msg = String.format("Writer %s 로 연결 종료합니다.", fileName);
System.out.println(msg);
}
}
public class Ftp {
private String host;
private int port;
private String path;
public Ftp(String host, int port, String path){
this.host = host;
this.port = port;
this.path = path;
}
public void connect(){ // 원격지에 커넥트
System.out.println("FTP Host : " + host+ "Port : " +port+"로 연결합니다."")
}
public void moveDirectory(){ //해당 디렉토리로 이동
System.out.println("FTP path : " + path+ "로 이동합니다.");
}
public void disConnect(){ //FTP연결 종료
System.out.println("FTP연결을 종료합니다..");
}
}
public class Main {
public static void main(String[] args) {
Ftp ftpClient = new Ftp("www.foo.co.kr", 22, "./home/etc");
ftpClient.connect();
ftpClient.moveDirectory();
Writer writer = new Writer("Text.tmp");
writer.fileConnect();
writer.write();
Reader reader = new Reader("text.tmp");
reader.fileConnect();
reader.fileRead();
reader.fileDisconnect();
writer.fileDisconnect();
ftpClient.disConnect();
}
}
현재 클라이언트가 다 의존성을 가지고 만들고있는데, 이부분을 facade객체를 만들어서 이 인터페이스를 활용!
-> SftpClient 라는 객체 만든다
public class SftpClient {
private Ftp ftp;
private Reader reader;
private Writer writer;
public SftpClient(Ftp ftp, Reader reader, Writer writer){
this.ftp = ftp;
this.reader = reader;
this.writer = writer;
//오버로딩
public SftpClient(String host, int port, String path, String fileName){
this.ftp = new Ftp(host, port, path);
this.reader = new Reader(fileName);
this.writer = new Writer(fileName);
}
public void connect(){
this.ftpProtocol.connect();
this.ftpProtocol.moveDirectory();
this.fileReader.fileConnect();
this.fileWriter.fileConnect();
}
public void write(String content){
this.fileWriter.fileWrite(content);
}
public String read(){
return this.fileReader.fileRead();
}
public void disConnect(){
this.fileReader.fileDisconnect();
this.fileWriter.fileDisconnect();
this.ftpProtocol.disConnect();
}
}
-> main 코드가 이렇게 변함
SftpClient sftpClient = new SftpClient("www.foo,co.kr", 22, "/home/etc", "text.tmp");
sftpClient.connect();
sftpClient.write();
sftpClient.rear();
sftpClient.disconnect();
전략(Strategy)패턴
- 유사한 행위들을 캡슐화하여 객체의 행위를 바꾸고 싶은 경우 직접 변경하는것이 아닌 전략만 변경하여 유연하게 확장하는 패턴
- SOLID중에서 개방폐쇄원칙(OCP)과 의존역전원칙(DIP) 따름
- 전략에 따라 결과가 달라짐!!
예제 ) 인코딩관련 - 아래 3가지가 다 있어야 함
1) 전략메서드를 가진 전략객체 (Normal Strategy, Base64 strategy)
2) 전략객체를 사용하는 컨텍스트 (Encoder)
3) 전략객체를 생성해 컨텍스트에 주입하는 클라이언트 -> 메인 메소드에 구현
메인메소드
Encoder encoder = new Encoder();
//base64의 전략
EncodingStrategy base64 = new Base64Strategy();
//normal의 전략
EncodingStrategy normal = new NormalStrategy();
//전략 집어넣기
String message = "hello java";
encoder.setEncodingStrategy(base64);
String base64Result = encoder.getMessage(message);
System.out.println(base64lResult);
encoder.setEncodingStrategy(normal);
String normalResult = encoder.getMessage(message);
System.out.println(normalResult);
encoder.setEncodingStrategy(new AppendStrategy());
String appendResult = encoder.getMessage(message);
System.out.println(appendResult); //출력 : ABCDhello java
public class NormalStrategy implements EncodingStrategy {
@Override
public String encode(String text) {
return text;
}
}
public class Base64Strategy implements EncodingStrategy{
@Override
public String encode(String text) {
return Base64.getEncoder().encodeToString(text.getBytes());
}
}
public class AppendStrategy implements EncodingStrategy{
@Override
public String encode(String text) {
return "ABCD" + text;
}
}
public class Encoder {
//그때그때마다 전략을 주입받음
private EncodingStrategy encodingStrategy;
//인코더 세팅을 위함
public String getMessage(String message){ //각각의 전략에 따라 결과가 달라짐
return encodingStrategy.encode(message);
}
public void setEncodingStrategy(EncodingStrategy encodingStrategy){
this.encodingStrategy = encodingStrategy;
}
}
public interface EncodingStrategy {
String encode(String text); //텍스트를 받아서 encode시켜줌
}
'스프링 입문' 카테고리의 다른 글
스프링 입문 3.3 URI 설계패턴 (1) | 2024.01.02 |
---|---|
스프링 입문 3.1 웹 개발이란 (1) | 2024.01.02 |
스프링 입문 2.2 프록시(Proxy), 데코레이터(Decorator) 패턴 (0) | 2023.12.30 |
스프링 입문 2.1 싱글톤(singleton) 패턴 & 어댑터(adapter) 패턴 (1) | 2023.12.26 |
스프링 입문 2. 디자인패턴이란? (2) | 2023.12.26 |