구조 디자인패턴(3) -플라이웨이트 패턴, 프록시 패턴
플라이웨이트 패턴
객체를 가볍게 만들어 메모리사용을 줄이는패턴
- 자주변하는속성과 변하지않는 속성을 분리하고 재사용하여 매모리사용을 줄일수있다.
public class Character {
private char value;
private String color;
private String fontFamily;
private int fontSize;
public Character(char value, String color, String fontFamily, int fontSize) {
this.value = value;
this.color = color;
this.fontFamily = fontFamily;
this.fontSize = fontSize;
}
}
public static void main(String[] args) {
Character c1 = new Character('h', "white", "Nanum", 12);
Character c2 = new Character('e', "white", "Nanum", 12);
Character c3 = new Character('l', "white", "Nanum", 12);
Character c4 = new Character('l', "white", "Nanum", 12);
Character c5 = new Character('o', "white", "Nanum", 12);
}
폰트패밀리,폰트사이즈 색상등이 겹쳐서 메모리를 많이 차지하고있는듯한 모습이다.
public final class Font {
final String family;
final int size;
/**
* 플라이웨이트에해당하는 인스턴스는 불변해야한다.
* 다른여러 객체에서 공유하는 객체이기때문이다.
* 클래스에 final 필드값에 final을 붙였다.
*/
public Font(String family, int size) {
this.family = family;
this.size = size;
}
public String getFamily() {
return family;
}
public int getSize() {
return size;
}
}
플라이웨이트 인스턴스는 불변해야한다.
public class Character {
private char value;
private String color;
private Font font;
public Character(char value, String color, Font font) {
this.value = value;
this.color = color;
this.font = font;
}
}
public class FontFactory {
private Map<String, Font> cache = new HashMap<>();
public Font getFont(String font) {
if (cache.containsKey(font)) {
return cache.get(font);
} else {
String[] split = font.split(":");
Font newFont = new Font(split[0], Integer.parseInt(split[1]));
cache.put(font, newFont);
return newFont;
}
}
}
public static void main(String[] args) {
FontFactory fontFactory = new FontFactory();
Character c1 = new Character('h', "white", fontFactory.getFont("nanum:12"));
Character c2 = new Character('e', "white", fontFactory.getFont("nanum:12"));
Character c3 = new Character('l', "white", fontFactory.getFont("nanum:12"));
}
플라이웨이트 패턴
장점
- 애플리케이션에서 사용하는 메모리를 줄일수있다.
단점
- 코드의 복잡도가 증가한다.
숫자나 문자열비교할때 == 쓰지말자
프록시 패턴
특정객체에 대한 접근을 제어하거나 기능을 추가할수있는 패턴
- 초기화지연, 접근제어, 로깅, 캐싱등 다양하게 사용할수있다.
프록시 = 인터페이스를 필드값으로 가지고있다.
RealSubject 를 참조하기위함이다.
public class GameService {
public void startGame() {
System.out.println("이 자리에 오신 여러분을 진심으로 환영합니다.");
}
// 코드의 실행시간을 확인하고싶은데 코드는 변경할수없다.
}
public static void main(String[] args) throws InterruptedException {
GameService gameService = new GameService();
gameService.startGame();
}
// 코드를 추가하면 시간을 잴수있겠지만, 코드를 유지하면서 시행하고싶다.
public class GameServiceProxy extends GameService {
@Override
public void startGame() {
long before = System.currentTimeMillis();
super.startGame();
System.out.println(System.currentTimeMillis() - before);
}
}
public static void main(String[] args) {
GameService gameService = new GameServiceProxy();
gameService.startGame();
}
클래스를 하나 만들어 상속으로 해결한다
GameService 를 고칠수없는경우엔 해결법이 될수있겠다.
하지만 손댈수있는경우라면
public interface GameService {
void startGame();
}
public class DefaultGameService implements GameService{
@Override
public void startGame() {
System.out.println("이자리에 오신걸 환영합니다");
}
}
GameService를 인터페이스로 만들고
public class GameServiceProxy implements GameService {
private GameService gameService;
// public GameServiceProxy(DefaultGameService defaultGameService) {
// this.gameService = gameService;
// }
@Override
public void startGame() {
long before = System.currentTimeMillis();
if (gameService == null) {
this.gameService = new DefaultGameService();
}
gameService.startGame();
System.out.println(System.currentTimeMillis() - before);
}
}
public static void main(String[] args) {
// GameService gameService = new GameServiceProxy(new DefaultGameService());
//gameService.startGame();
GameService gameService = new GameServiceProxy();
gameService.startGame();
}
클라이언트가 DefaultGameService를 쓰긴써야되는데 GameServiceProxy를 거쳐서 사용하고있다.
프록시패턴의 장점
- 기존코드를 변경하지않고 새로운기능을 추가할수있다.
- 기존코드가 해야하는일만 유지할수있다.
- 기능추가 및 초기화지연등으로 다양하게 활용할수있다.
단점
- 코드의 복잡도가 증가한다.
사용사례
public static void main(String[] args) {
ProxyInJava proxyInJava = new ProxyInJava();
proxyInJava.dynamicProxy();
}
private void dynamicProxy() {
GameService gameServiceProxy = getGameServiceProxy(new DefaultGameService());
gameServiceProxy.startGame();
}
private GameService getGameServiceProxy(GameService target) {
return (GameService) Proxy.newProxyInstance(this.getClass().getClassLoader(),
new Class[]{GameService.class}, (proxy, method, args) -> {
System.out.println("O");
method.invoke(target, args);
System.out.println("ㅁ");
return null;
});
}
동적으로 런타임시에 생성되는 프록시
이러한기능들이 여러메서드에 적용해야된다면
비슷한코드가 많이 들어가지만 동적으로 런타임시에 생성해서 조금더 효율적으로 사용할수있다.
스프링의 AOP
여러곳에 흩어져있는 개념을 한곳에 모아서 처리하게끔 하는개념
@Service
public class GameService {
public void startGame() {
System.out.println("이 자리에 오신 여러분을 진심으로 환영합니다.");
}
}
@Aspect
@Component
public class PerfAspect {
@Around("bean(gameService)")
public void timestamp(ProceedingJoinPoint point) throws Throwable {
long before = System.currentTimeMillis();
point.proceed();
System.out.println(System.currentTimeMillis() - before);
}
}
스프링이 관리하는 Bean에만 Aspect를 적용할수있어서
@Component 로 빈으로 등록.
스프링이 구동될떄 동적으로 Bean을 만들어서 등록해주고
프록시빈을 주입받아서 사용하게된다.
참조: https://www.inflearn.com/course/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4#
Author And Source
이 문제에 관하여(구조 디자인패턴(3) -플라이웨이트 패턴, 프록시 패턴), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@dudwls0505/구조-디자인패턴3-플라이웨이트-패턴-프록시-패턴저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)