구조 패턴 - 어댑터, 브리지, 컴포지트, 데코레이터, 퍼싸드, 플라이웨이트, 프록시
구조 패턴은 클래스나 객체를 조합해 더 큰 구조를 만드는 패턴들을 의미한다
1.어댑터 패턴
- 호환성이 없는 클래스들의 인터페이스를 다른 클래스가 이용할 수 있도록 변환해주는 패턴
- 기존의 클래스를 사용허고 싶으나 인터페이스가 일치하지 않을떄 사용
(https://lktprogrammer.tistory.com/29)
String content = "hello";
Parser_B parserB = new Parser_B(content);
Parser_C parserC = new Parser_C(content));
parserB.Parsing();
parserC.C_Parsing();
B 클래스와 C 클래스의 메서드명이 다르다
public interface Parser {
public void Do_Parsing();
}
public class Main {
public static void main(String argsp[]){
String st = "hello";
Adapter_B_Parser parser1 = new Adapter_B_Parser(new Parser_B(st));
Adapter_C_Parser parser2 = new Adapter_C_Parser(new Parser_C(st));
parser1.Do_Parsing();
parser2.Do_Parsing();
}
}
공통 인터페이스를 설정하고
이에 맞춰 어댑터 클래스를 구현하면
메서드명을 통일해서 사용할 수 있다.
2.브리지 패턴
- 구현부와 추상층을 분리, 서로 독립적으로 확장할 수 있도록 구성한다
-기능과 구현을 두 개의 별도의 클래스로 구현한다
public class Main {
public static void main(String argsp[]){
Animal tiger = new Tiger(new Hunting_Method2());
Animal bird = new Bird(new Hunting_Method1());
tiger.hunt();
bird.hunt();
}
}
각 동물들은 육지/수상/공중에 따라 서로 다른 사냥법을 갖는다.
3개의 사냥 방법 클래스를 구현하고
각 애니멀 클래스들은 본인에게 맞는 사냥 방법 인스턴스를 인자로 생성한다
3.컴포지트 패턴
- 여러 객체를 지닌 복합 객체와 단일 객체를 구분 없이 다루고자 할 때 사용하는 패턴
- 객체들을 트리 구조로 구성, 복합 객체 안에 복합/단일 객체가 존재할 수 있다
public class Main {
public static void main(String argsp[]){
Directory root = new Directory("root");
Directory bin = new Directory("bin");
Directory Lkt = new Directory("Lkt");
File file1 = new File("file1");
File file2 = new File("file2");
File file3 = new File("file3");
File file4 = new File("file3");
root.add(file1); //루트 디렉토리에 file1 포함
bin.add(file2); //bin 디렉토리에 file2 포함
bin.add(file3); //bin 디렉토리에 file3 포함
Lkt.add(file4); //Lkt 디렉토리에 file4 포함
root.add(Lkt); //root 디렉토리에 Lkt 디렉토리 포함
root.add(bin); //root 디렉토리에 bin 디렉토리 포함
root.PrintList("");
}
}
파일 시스템 예제
public class Main {
public static void main(String[] args) {
// 그래픽 도형 객체 생성
Graphic circle = new Circle();
Graphic line = new Line();
// 복합 그래픽 도형 생성 및 단일 객체 추가
CompositeGraphic composite = new CompositeGraphic();
composite.add(circle);
composite.add(line);
// 그래픽 도형을 그리는 메서드 호출
composite.draw();
}
}
원과 선의 단일 객체를 만들고
이를 조합한 특정 그림을 복합 객체로 사용 가능하다
4.데코레이터 패턴
- 객체간의 결합을 통해 (능)동적으로 기능을 확장할 수 있는 패턴
- 임의의 객체에 부가적인 기능 추가를 위해 다른 객체를 덧붙이는 방식으로 구현
// 무기 인터페이스
interface Weapon {
void attack();
}
// 기본 무기
class Sword implements Weapon {
@Override
public void attack() {
System.out.println("검으로 공격합니다.");
}
}
1.무기 인터페이스와 기본 무기 구현
abstract class WeaponDecorator implements Weapon {
protected Weapon decoratedWeapon;
public WeaponDecorator(Weapon decoratedWeapon) {
this.decoratedWeapon = decoratedWeapon;
}
@Override
public void attack() {
decoratedWeapon.attack();
}
}
2.데코레이터 추상 클래스
// 데코레이터: 무기에 화염 마법 추가
class FireDecorator extends WeaponDecorator {
public FireDecorator(Weapon decoratedWeapon) {
super(decoratedWeapon);
}
@Override
public void attack() {
super.attack();
System.out.println("화염 마법을 사용합니다.");
}
}
// 데코레이터: 무기에 전기 마법 추가
class LightningDecorator extends WeaponDecorator {
~~위와 동일~~
}
// 데코레이터: 무기에 얼음 속성 추가
class IceDecorator extends WeaponDecorator {
~~위와 동일~~
}
3.검에 불/얼음/전기를 인챈트하는 데코레이터
public class Main {
public static void main(String[] args) {
// 기본 무기인 검을 생성합니다.
Weapon sword = new Sword();
System.out.println("기본 무기:");
sword.attack();
// 얼음 마법이 장착된 검을 생성합니다.
Weapon iceSword = new IceDecorator(sword);
System.out.println("\n얼음 마법이 장착된 검:");
iceSword.attack();
// 화염 마법이 장착된 얼음 검을 생성합니다.
Weapon iceFireSword = new FireDecorator(iceSword);
System.out.println("\n화염 마법이 장착된 얼음 검:");
iceFireSword.attack();
// 전기 마법이 장착된 얼음 화염 검을 생성합니다.
Weapon ultimateSword = new LightningDecorator(iceFireSword);
System.out.println("\n전기 마법이 장착된 얼음 화염 검:");
ultimateSword.attack();
}
}
기본 무기 객체에 인챈트 마법을 덧붙여 결합하는 방식으로 능동적인 확장이 가능하다.
5.퍼사드 패턴
-복잡한 서브 클래스들의 상위에 인터페이스를 구성해 서브클래스의 기능을 간단하게 사용할 수 있도록 함
- 서브 클래스 사이의 통합 인터페이스를 제공하는 Wrapper 객체가 필요하다
public class Facade {
private String beverage_Name ="";
private String Movie_Name="";
public Facade(String beverage,String Movie_Name){
this.beverage_Name=beverage_Name;
this.Movie_Name=Movie_Name;
}
public void view_Movie(){
Beverage beverage = new Beverage(beverage_Name);
Remote_Control remote= new Remote_Control();
Movie movie = new Movie(Movie_Name);
beverage.Prepare();
remote.Turn_On();
movie.Search_Movie();
movie.Charge_Movie();
movie.play_Movie();
}
}
영화를 보려면
음료수 준비 -> 리모콘 켜기 -> 영화 검색 -> 결제 -> 재생의 과정을 거쳐야한다.
이때 음료수 / 리모콘 / 영화 3개의 서브 클래스를 하나로 묶는 facade 인터페이스로 랩핑하면
public class Facade {
public void view(){
Facade facade = new Facade("콜라","어벤져스");
facade.view_Movie();
}
}
메인 함수에선 음료수와 영화 2개의 인자만 넣으면
서브클래스의 복잡한 구조를 몰라도 간단하게 사용 가능하다.
클라이언트와 서브시스템들 간의 중간 완충재를 추가하는 느낌.
6.플라이웨이트 패턴
- 인스턴스를 매번 새로 생성하지 않고 가능한 공유해서 사용 하여 메모리 절약
(https://lee1535.tistory.com/106)
public class ShapeFactory {
private static final HashMap<String, Circle> circleMap = new HashMap<>();
public static Shape getCircle(String color) {
Circle circle = (Circle)circleMap.get(color);
if(circle == null) {
circle = new Circle(color);
circleMap.put(color,circle);
System.out.println("==== 새로운 객체 생성 : " + color + "색 원 ====" );
}
return circle;
}
}
매번 circle 객체를 만들지 말고 기존 객체에 정보를 덧씌워 재활용한다
= 이전 객체의 정보가 필요하면 사용 불가
7.프록시 패턴
- 접근이 어려운 객체와 이에 연결하려는 객체 사이에 인터페이스 역할을 수행하는 패턴
- 네트워크 연결, 메모리의 대용량 객체 접근에 주로 이용
public interface Subject {
public void Show_Name();
public void set_Name(String name);
public void Complicated_Work();
}
인터페이스 정의
프록시와 실제 클래스는 같은 인터페이스를 지닌다.
간단한 작업은 프록시가 처리하고
프록시로 처리 불가능한 복잡한 작업일때엔 실제 클래스를 호출한다
public class Main {
public static void main(String argsp[]){
proxy proxy1 = new proxy();
proxy1.set_Name("홍길동");
proxy1.Show_Name();
proxy1.Complicated_Work();
}
}
메인 함수에선 프록시만 호출해서 사용하면 된다.
https://lktprogrammer.tistory.com/category/Study/%EB%94%94%EC%9E%90%EC%9D%B8%20%ED%8C%A8%ED%84%B4
'Study/디자인 패턴' 카테고리의 글 목록
IT / 프로그래밍 관련 강의 자료를 공유하고 딱딱한 일상에서 벗어나 여행/맛집 일상을 공유하는 블로그입니다 ^^
lktprogrammer.tistory.com