CS/기타

구조 패턴 - 어댑터, 브리지, 컴포지트, 데코레이터, 퍼싸드, 플라이웨이트, 프록시

길용쓰 2023. 10. 6. 13:59

구조 패턴은 클래스나 객체를 조합해 더 큰 구조를 만드는 패턴들을 의미한다

 

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