디자인패턴-구조패턴

Extreme Coding·2022년 1월 8일
0

디자인패턴

목록 보기
1/2

구조패턴 이란?

  • 구조패턴(Structal pattern)은 더 큰 구조를 형성하기 위해 어떻게 클래스와 객체를 합성하는가와 관련된 패턴이다.
    7개: Adapter(적응자), Bridge(가교), Composite(복합체), Decorator(장식자), facade(퍼사드), flyweight(플라이급), proxy(프록시)가 있다.

Adapter(적응자)

의도

  • 클래스의 인터페이스를 사용자가 기대하는 인터페이스 형태로 변화시킵니다.
    서로 일치하지 않는 인터페이스를 갖는 클래스들을 함께 동작시킵니다.

Also known as

  • Wrapper

클래스 다이어그램

코드


import lombok.extern.slf4j.Slf4j;

@Slf4j
final class FishingBoat {
    void sail() {
        log.info("The fishing boat is sailing");
    }
}

interface RowingBoat {
    void row();
}

class FishingBoatAdapter implements RowingBoat {

    private final FishingBoat boat = new FishingBoat();

    public final void row() {
        boat.sail();
    }
}

final class Captain {

    private RowingBoat rowingBoat;

    public Captain(RowingBoat rowingBoat) {
        super();
        this.rowingBoat = rowingBoat;
    }

    void row() {
        rowingBoat.row();
    }
}

public class App {
    public static void main(final String[] args) {
        Captain captain = new Captain(new FishingBoatAdapter());
        captain.row();
    }
}

활용성

  • 기존 클래스를 사용하고 싶은데 인터페이스가 맞지 않을 때
  • 아직 예측하지 못한 클래스나 실제 관련되지 않는 클래스들이 기존 클래스를 재사용하고자 하지만, 이미 정의된 재사용 가능한 클래스가 지금 요청하는 인터페이스를 꼭 정의하고 있지 않을 때. 다시 말해, 이미 만든 것을 재사용하고자 하나 이 재사용 가능한 라이브러리를 수정할 수 없을 때
  • 이미 존재하는 여러 개의 서브클래스를 사용해야 하는데, 이 서브클래스들의 상속을 통해서 이들의 인터페이스를 다 개조한다는 것이 현실성이 없을 때. 객체 적응자를 써서 부모 클래스의 언터페이스를 변형하는 것이 더 바람직함

Bridge(가교)

의도

  • 구현에서 추상을 분리하여, 이들이 독립적으로 다양성을 가질 수 있도록 합니다.

Also known as

  • Handle/Body

클래스 다이어그램

코드

import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;

interface Enchantment {

    void onActivate();

    void apply();

    void onDeactivate();
}

@Slf4j
class FlyingEnchantment implements Enchantment {
    @Override
    public void onActivate() {
        log.info("The item begins to glow faintly.");
    }

    @Override
    public void apply() {
        log.info("The item flies and strikes the enemies finally returning to owner's hand.");
    }

    @Override
    public void onDeactivate() {
        log.info("The item's glow fades.");
    }
}

@Slf4j
class SoulEatingEnchantment implements Enchantment {

    @Override
    public void onActivate() {
        log.info("The item spreads bloodlust.");
    }

    @Override
    public void apply() {
        log.info("The item eats the soul of enemies.");
    }

    @Override
    public void onDeactivate() {
        log.info("Bloodlust slowly disappears.");
    }
}

interface Weapon {

    void wield();

    void swing();

    void unwield();

    Enchantment getEnchantment();
}

@Slf4j
@AllArgsConstructor
class Hammer implements Weapon {

    private final Enchantment enchantment;

    @Override
    public void wield() {
        log.info("The hammer is wielded.");
        enchantment.onActivate();
    }

    @Override
    public void swing() {
        log.info("The hammer is swung.");
        enchantment.apply();
    }

    @Override
    public void unwield() {
        log.info("The hammer is unwielded.");
        enchantment.onDeactivate();
    }

    @Override
    public Enchantment getEnchantment() {
        return enchantment;
    }
}

@Slf4j
@AllArgsConstructor
class Sword implements Weapon {

    private final Enchantment enchantment;

    @Override
    public void wield() {
        log.info("The sword is wielded.");
        enchantment.onActivate();
    }

    @Override
    public void swing() {
        log.info("The sword is swung.");
        enchantment.apply();
    }

    @Override
    public void unwield() {
        log.info("The sword is unwielded.");
        enchantment.onDeactivate();
    }

    @Override
    public Enchantment getEnchantment() {
        return enchantment;
    }
}

@Slf4j
public class App {

    public static void main(String[] args) {
        log.info("The knight receives an enchanted sword.");
        var enchantedSword = new Sword(new SoulEatingEnchantment());
        enchantedSword.wield();
        enchantedSword.swing();
        enchantedSword.unwield();

        log.info("The valkyrie receives an enchanted hammer.");
        var hammer = new Hammer(new FlyingEnchantment());
        hammer.wield();
        hammer.swing();
        hammer.unwield();
    }
}

활용성

  • 추상적 개념과 이에 대한 구현 사이의 지속적인 종속 관계를 피하고 싶을 때. 이를테면, 런타임에 구현 방법을 선택하거나 구현 내용을 변경하고 싶을 때가 여기에 해당합니다.
  • 추상적 개념과 구현 모두가 독립적으로 서브클래싱을 통해 확장되어야 할 때. 이때, 가교 패턴은 개발자가 구현을 또 다른 추상적 개념과 연결할 수 있게 할 뿐 아니라, 각각을 독립적으로 확장 가능하게 합니다.
  • 추상적 개념에 대한 구현 내용을 변경하는 것이 다른 관련 프로그램에 아무런 영향을 주지 않아야 할 때. 즉, 추상적 개념에 해당하는 클래스를 사용하는 코드들은 구현 클래스가 변경되었다고 해서 다시 컴파일되지 않아야 합니다.
  • 여러 객체들에 걸쳐 구현을 공유하고자 하며(참조 카운팅 방법 등) 또 이런 사실을 사용자 쪽에 공개하고 싶지 않을 때

결과

  • 인터페이스와 구현 분리 - 구현이 인터페이스에 얽매이지 않게 됩니다.
  • 확장성 제고. 독립적으로 확장할 수 있습니다.
  • 구현 세부 사항을 사용자에게서 숨기기. 상세한 구현 내용을 사용자에게서 은닉할 수 있습니다.

Composite(복합체)

의도

  • 부분과 전체의 계층을 표현하기 위해 객체들을 모아 트리 구조로 구성합니다. 사용자로 하여금 개별 객체와 복합 객체를 모두 동일하게 다룰 수 있도록 하는 패턴입니다.

클래스 다이어그램

코드

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;

abstract class LetterComposite {

    private final List<LetterComposite> children = new ArrayList<>();

    public void add(LetterComposite letter) {
        children.add(letter);
    }

    public int count() {
        return children.size();
    }

    protected void printThisBefore() {
    }

    protected void printThisAfter() {
    }

    public void print() {
        printThisBefore();
        children.forEach(LetterComposite::print);
        printThisAfter();
    }
}

@RequiredArgsConstructor
class Letter extends LetterComposite {

    private final char character;

    @Override
    protected void printThisBefore() {
        System.out.print(character);
    }
}

class Word extends LetterComposite {

    public Word(List<Letter> letters) {
        letters.forEach(this::add);
    }

    public Word(char... letters) {
        for (char letter : letters) {
            this.add(new Letter(letter));
        }
    }

    @Override
    protected void printThisBefore() {
        System.out.print(" ");
    }
}

class Sentence extends LetterComposite {

    public Sentence(List<Word> words) {
        words.forEach(this::add);
    }

    @Override
    protected void printThisAfter() {
        System.out.print(".\n");
    }
}

class Messenger {
    public Messenger() {
        super();
    }

    public LetterComposite messageFromOrcs() {
        var words = List.of(
                new Word('W', 'h', 'e', 'r', 'e'),
                new Word('t', 'h', 'e', 'r', 'e'),
                new Word('i', 's'),
                new Word('a'),
                new Word('w', 'h', 'i', 'p'),
                new Word('t', 'h', 'e', 'r', 'e'),
                new Word('i', 's'),
                new Word('a'),
                new Word('w', 'a', 'y')
        );
        return new Sentence(words);
    }

    public LetterComposite messageFromElves() {
        var words = List.of(
                new Word('M', 'u', 'c', 'h'),
                new Word('w', 'i', 'n', 'd'),
                new Word('p', 'o', 'u', 'r', 's'),
                new Word('f', 'r', 'o', 'm'),
                new Word('y', 'o', 'u', 'r'),
                new Word('m', 'o', 'u', 't', 'h')
        );
        return new Sentence(words);
    }
}

@Slf4j
public class App {

    public static void main(String[] args) {
        var messenger = new Messenger();
        log.info("Message from the orcs: ");
        messenger.messageFromOrcs().print();

        log.info("Message from the elves: ");
        messenger.messageFromElves().print();
    }
}

활용성

  • 부분 - 전체의 객체 계통을 표현하고 싶을 때
  • 사용자가 객체의 합성으로 생긴 복합 객체와 개개의 객체 사이의 차이를 알지 않고도 자기 일을 할 수 있도록 만들고 싶을 때. 사용자는 복합 구조(composite structure)의 모든 객체를 똑같이 취급하게 됩니다.

결과

  • 기본 객체와 복합 객체로 구성된 하나의 일관된 클래스 계통을 정의합니다.
  • 사용자의 코드가 단순해집니다. 사용자 코드는 복합 구조이나 단일 객체와 동일하게 다루는 코드로 작성되기 때문입니다. 즉, 사용자는 복합 구조인지 단일 구조인지조차 모르고 개발할 수 있습니다.
  • 새로운 종류의 구성요소를 쉽게 추가할 수 있습니다.
  • 설계가 지나치게 범용성을 많이 가집니다.

Decorator(장식자)

의도

  • 객체에 동적으로 새로운 책임을 추가할 수 있게 합니다. 기능을 추가하려면, 서브클래스를 생성하는 것보다 융통성 있는 방법을 제공합니다.

Also known as

  • Wrapper

클래스 다이어그램

코드

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

interface Troll {

    void attack();

    int getAttackPower();

    void fleeBattle();
}

@Slf4j
class SimpleTroll implements Troll {

    @Override
    public void attack() {
        log.info("The troll tries to grab you!");
    }

    @Override
    public int getAttackPower() {
        return 10;
    }

    @Override
    public void fleeBattle() {
        log.info("The troll shrieks in horror and runs away!");
    }
}

@Slf4j
@RequiredArgsConstructor
class ClubbedTroll implements Troll {

    private final Troll decorated;

    @Override
    public void attack() {
        decorated.attack();
        log.info("The troll swings at you with a club!");
    }

    @Override
    public int getAttackPower() {
        return decorated.getAttackPower() + 10;
    }

    @Override
    public void fleeBattle() {
        decorated.fleeBattle();
    }
}

@Slf4j
public class App {

    public static void main(String[] args) {

        // simple troll
        log.info("A simple looking troll approaches.");
        var troll = new SimpleTroll();
        troll.attack();
        troll.fleeBattle();
        log.info("Simple troll power: {}.\n", troll.getAttackPower());

        // change the behavior of the simple troll by adding a decorator
        log.info("A troll with huge club surprises you.");
        var clubbedTroll = new ClubbedTroll(troll);
        clubbedTroll.attack();
        clubbedTroll.fleeBattle();
        log.info("Clubbed troll power: {}.\n", clubbedTroll.getAttackPower());
    }
}

활용성

  • 동적으로 또한 투명하게, 다시 말해 다른 객체에 영향을 주지 않고 개개의 객체에 새로운 책임을 추가하기 위해 사용합니다.
  • 제거될 수 있는 책임에 대해 사용합니다.
  • 실제 상속으로 서브클래스를 계속 만드는 방법이 실질적이지 못할 때 사용합니다. 너무 많은 수의 독립된 확장이 가능할 때 모든 조합을 지원하기 위해 이를 상속으로 해결하면 클래스 수가 폭발적으로 많아지게 됩니다. 아니면, 클래스 정의가 숨겨지든가, 그렇지 않더라도 서브 클래싱을 할 수 없게 됩니다.

결과

  • 단순한 상속보다 설계의 융통성을 더 많이 증대시킬 수 있습니다.
  • 클래스 계통의 상부측 클래스에 많은 기능이 누적되는 상황을 피할 수 있습니다.
  • 장식자와 해당 그 장식자의 구성요소가 동일한 것은 아닙니다.
  • 장식자를 사용함으로써 작은 규모의 객체들이 많이 생깁니다.

Facade(퍼사드)

의도

  • 한 서브시스템 내의 인터페이스 집합에 대한 확일화된 하나의 인터페이스를 제공하는 패턴으로, 서브시스템을 사용하기 쉽도록 상위 수준의 인터페이스를 정의합니다.

클래스 다이어그램

코드

import lombok.extern.slf4j.Slf4j;

import java.util.Arrays;
import java.util.Collection;
import java.util.List;

class DwarvenGoldmineFacade {

    private final List<DwarvenMineWorker> workers;

    public DwarvenGoldmineFacade() {
        workers = List.of(
                new DwarvenGoldDigger(),
                new DwarvenCartOperator(),
                new DwarvenTunnelDigger());
    }

    public void startNewDay() {
        makeActions(workers, DwarvenMineWorker.Action.WAKE_UP, DwarvenMineWorker.Action.GO_TO_MINE);
    }

    public void digOutGold() {
        makeActions(workers, DwarvenMineWorker.Action.WORK);
    }

    public void endDay() {
        makeActions(workers, DwarvenMineWorker.Action.GO_HOME, DwarvenMineWorker.Action.GO_TO_SLEEP);
    }

    private static void makeActions(Collection<DwarvenMineWorker> workers, DwarvenMineWorker.Action... actions) {
        workers.forEach(worker -> worker.action(actions));
    }
}

@Slf4j
abstract class DwarvenMineWorker {

    public void goToSleep() {
        log.info("{} goes to sleep.", name());
    }

    public void wakeUp() {
        log.info("{} wakes up.", name());
    }

    public void goHome() {
        log.info("{} goes home.", name());
    }

    public void goToMine() {
        log.info("{} goes to the mine.", name());
    }

    private void action(Action action) {
        switch (action) {
            case GO_TO_SLEEP:
                goToSleep();
                break;
            case WAKE_UP:
                wakeUp();
                break;
            case GO_HOME:
                goHome();
                break;
            case GO_TO_MINE:
                goToMine();
                break;
            case WORK:
                work();
                break;
            default:
                log.info("Undefined action");
                break;
        }
    }

    public void action(Action... actions) {
        Arrays.stream(actions).forEach(this::action);
    }

    public abstract void work();

    public abstract String name();

    enum Action {
        GO_TO_SLEEP, WAKE_UP, GO_HOME, GO_TO_MINE, WORK
    }
}

@Slf4j
class DwarvenTunnelDigger extends DwarvenMineWorker {

    @Override
    public void work() {
        log.info("{} creates another promising tunnel.", name());
    }

    @Override
    public String name() {
        return "Dwarven tunnel digger";
    }
}

@Slf4j
class DwarvenGoldDigger extends DwarvenMineWorker {

    @Override
    public void work() {
        log.info("{} digs for gold.", name());
    }

    @Override
    public String name() {
        return "Dwarf gold digger";
    }
}

@Slf4j
class DwarvenCartOperator extends DwarvenMineWorker {

    @Override
    public void work() {
        log.info("{} moves gold chunks out of the mine.", name());
    }

    @Override
    public String name() {
        return "Dwarf cart operator";
    }
}

public class App {
    public static void main(String[] args) {
        var facade = new DwarvenGoldmineFacade();
        facade.startNewDay();
        facade.digOutGold();
        facade.endDay();
    }
}

활용성

  • 복잡한 서브시스템에 대한 단순한 인터페이스 제공이 필요할 때. 시스템 범위가 확장되면, 또한 구체적으로 설계되면 서브시스템은 계속 복잡해집니다. 또한 패턴을 적용하면 확장성을 고려하여 설계하기 때문에, 작은 클래스가 만들어지게 됩니다. 이런 과정은 서브시스템을 재사용 가능한 것으로 만들어 주고, 재정의할 수 있는 단위가 되도록 해 주기도 하지만, 실제 이런 상세한 재설계나 정제의 내용까지 파악할 필요가 없는 개바잘들에게는 복잡해진 각각의 클래스들을 다 이해하면서 서브시스템에 대한 단순하면서도 기본적인 인터페이스를 제공함으로써 대부분의 개발자들에게 적합한 클래스 형태를 제공합니다.
  • 추상 개념에 대한 구현 클래스와 사용자 사이에 너무 많은 종속성이 존재할 때. 퍼사드의 사용을 통해 사용자와 다른 서브시스템 간의 결합도를 줄일 수 있습니다. 즉, 서브시스템에 정의된 모든 인터페이스가 공개되면 빈번한 메서드 호출이 있을 수 있으나, 이런 호출은 단순한 형태로 통합하여 제공하고 나머지 부분은 내부적으로 처리함으로써 사용자와 서브시스템 사이의 호출 횟수는 실질적으로 감소하게 되는 효과를 갖습니다.
  • 서브시스템을 계층화시킬 때. 퍼사드 패턴을 사용하여 각 서브시스템의 계층에 대한 접근점을 제공합니다. 서브시스템이 다른 서브시스템에 종속적이라 하더라도, 각자가 제공하는 퍼사드를 통해서만 대화를 진행하게 함으로써 서브시스템 간의 종속성을 줄일 수 있습니다. 이로써 서브시스템 내부 설계의 변경이 다른 서브시스템에 독립적으로 자유롭게 될 수 있는 것입니다.

결과

  • 서브시스템의 구성요소를 보호할 수 있습니다. 이로써 사용자가 다루어야 할 객체의 수가 줄어들며, 서브시스템을 쉽게 사용할 수 있습니다.
  • 서브시스템과 사용자 코드 간의 결합도를 더욱 약하게 만듭니다.
  • 응용프로그램 쪽에서 서브시스템 클래스를 사용하는 것을 완전히 막지는 않습니다. 그러므로 Facde를 사용할지 서브시스템 클래스를 직접 사용할지 결정할 수 있습니다.

Flyweight(플라이급)

의도

  • 공유를 통해 많은 수의 소립 객체들을 효과적으로 지원합니다.

클래스 다이어그램

코드

import lombok.extern.slf4j.Slf4j;

import java.util.EnumMap;
import java.util.List;
import java.util.Map;

enum PotionType {
    HEALING, INVISIBILITY, STRENGTH, HOLY_WATER, POISON
}

class PotionFactory {

    private final Map<PotionType, Potion> potions;

    public PotionFactory() {
        potions = new EnumMap<>(PotionType.class);
    }

    Potion createPotion(PotionType type) {
        var potion = potions.get(type);
        if (potion == null) {
            switch (type) {
                case HEALING:
                    potion = new HealingPotion();
                    potions.put(type, potion);
                    break;
                case HOLY_WATER:
                    potion = new HolyWaterPotion();
                    potions.put(type, potion);
                    break;
                case INVISIBILITY:
                    potion = new InvisibilityPotion();
                    potions.put(type, potion);
                    break;
                case POISON:
                    potion = new PoisonPotion();
                    potions.put(type, potion);
                    break;
                case STRENGTH:
                    potion = new StrengthPotion();
                    potions.put(type, potion);
                    break;
                default:
                    break;
            }
        }
        return potion;
    }
}

interface Potion {
    void drink();
}

@Slf4j
class InvisibilityPotion implements Potion {

    @Override
    public void drink() {
        log.info("You become invisible. (Potion={})", System.identityHashCode(this));
    }
}

@Slf4j
class StrengthPotion implements Potion {

    @Override
    public void drink() {
        log.info("You feel strong. (Potion={})", System.identityHashCode(this));
    }
}

@Slf4j
class HealingPotion implements Potion {

    @Override
    public void drink() {
        log.info("You feel healed. (Potion={})", System.identityHashCode(this));
    }
}

@Slf4j
class HolyWaterPotion implements Potion {

    @Override
    public void drink() {
        log.info("You feel blessed. (Potion={})", System.identityHashCode(this));
    }
}

@Slf4j
class PoisonPotion implements Potion {

    @Override
    public void drink() {
        log.info("Urgh! This is poisonous. (Potion={})", System.identityHashCode(this));
    }
}

@Slf4j
class AlchemistShop {

    private final List<Potion> topShelf;
    private final List<Potion> bottomShelf;

    /**
     * Constructor.
     */
    public AlchemistShop() {
        var factory = new PotionFactory();
        topShelf = List.of(
                factory.createPotion(PotionType.INVISIBILITY),
                factory.createPotion(PotionType.INVISIBILITY),
                factory.createPotion(PotionType.STRENGTH),
                factory.createPotion(PotionType.HEALING),
                factory.createPotion(PotionType.INVISIBILITY),
                factory.createPotion(PotionType.STRENGTH),
                factory.createPotion(PotionType.HEALING),
                factory.createPotion(PotionType.HEALING)
        );
        bottomShelf = List.of(
                factory.createPotion(PotionType.POISON),
                factory.createPotion(PotionType.POISON),
                factory.createPotion(PotionType.POISON),
                factory.createPotion(PotionType.HOLY_WATER),
                factory.createPotion(PotionType.HOLY_WATER)
        );
    }

    public final List<Potion> getTopShelf() {
        return List.copyOf(this.topShelf);
    }

    public final List<Potion> getBottomShelf() {
        return List.copyOf(this.bottomShelf);
    }

    public void drinkPotions() {
        log.info("Drinking top shelf potions");
        topShelf.forEach(Potion::drink);
        log.info("Drinking bottom shelf potions");
        bottomShelf.forEach(Potion::drink);
    }
}

public class App {
    public static void main(String[] args) {
        // create the alchemist shop with the potions
        var alchemistShop = new AlchemistShop();
        // a brave visitor enters the alchemist shop and drinks all the potions
        alchemistShop.drinkPotions();
    }
}

활용성

  • 응용프로그램이 대량의 객체를 사용해야 할 때
  • 객체의 수가 너무 많아져 저장 비용이 너무 높아질 때
  • 대부분의 객체 상태를 부가적인 것으로 만들 수 있을 때
  • 부가적인 속성들을 제거한 후 객체들을 조사해 보니 객체의 많은 묶음이 비교적 적은 수의 공유된 객체로 대체될 수 있을 때. 현재 서로 다른 객체로 간주한 이유는 이들 부가적인 속성 때문이었지 본질이 달랐던 것은 아닐 때
  • 응용프로그램이 객체의 정체성에 의존하지 않을 때. 플라이급 객체들은 고유 될 수 있음을 의미하는데, 식별자가 있다는 것은 서로 다른 객체로 구별해야 한다는 의미이므로 플라이급 객체를 사용할 수 없습니다.

결과

  • 공유해야 하는 인스턴스의 전체 수를 줄일 수 있습니다.
  • 객체별 본질적 상태의 양을 줄일 수 있습니다.
  • 부가적인 상태는 연산되거나 저장될 수 있습니다.

Proxy(프록시)

의도

  • 다른 객체에 대한 접근을 제어하기 위한 대리자 또는 자리채움자 역할을 하는 객체를 둡니다.

Also known as

  • Surrogate

클래스 다이어그램

코드

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

interface WizardTower {
    void enter(Wizard wizard);
}

@Slf4j
class WizardTowerProxy implements WizardTower {

    private static final int NUM_WIZARDS_ALLOWED = 3;

    private int numWizards;

    private final WizardTower tower;

    public WizardTowerProxy(WizardTower tower) {
        this.tower = tower;
    }

    @Override
    public void enter(Wizard wizard) {
        if (numWizards < NUM_WIZARDS_ALLOWED) {
            tower.enter(wizard);
            numWizards++;
        } else {
            log.info("{} is not allowed to enter!", wizard);
        }
    }
}

@Slf4j
class IvoryTower implements WizardTower {
    public void enter(Wizard wizard) {
        log.info("{} enters the tower.", wizard);
    }
}

@RequiredArgsConstructor
class Wizard {

    private final String name;

    @Override
    public String toString() {
        return name;
    }
}

public class App {
    public static void main(String[] args) {
        var proxy = new WizardTowerProxy(new IvoryTower());
        proxy.enter(new Wizard("Red wizard"));
        proxy.enter(new Wizard("White wizard"));
        proxy.enter(new Wizard("Black wizard"));
        proxy.enter(new Wizard("Green wizard"));
        proxy.enter(new Wizard("Brown wizard"));
    }
}

활용성

  • 원격지 프록시
  • 가상 프록시
  • 보호용 프록시
  • 스마트 참조자 : 실제 객체에 접근이 일어날 때 추가적인 행동을 수행합니다.
    1. 실제 객체에 대한 참조 횟수를 저장하다가 더는 참조가 없을 때 해당 객체를 자동으로 없앱니다.(스마트 포인터)
    1. 맨 처음 참조되는 시점에 영속적 저장소의 객체를 메모리로 옮깁니다.
      3. 실제 객체에 접근하기 전에, 다른 객체가 그것을 변경하지 못하도록 실제 객체에 대해 잠금을 겁니다.

결과

  • 원격지 프록시는 객체가 다른 주소 공간에 존재한다는 사실을 숨길 수 있습니다.
  • 가상 프록시는 요구에 따라 객체를 생성하는 등 처리를 최적화할 수 있습니다.
  • 보호용 프록시 및 스마트 참조자는 객체가 접근할 때마다 추가 관리를 책임집니다. 객체를 생성할 것인지 삭제할 것인지를 관리합니다.

참고

profile
나의 개발 일기장!

0개의 댓글