Proxy Pattern (프록시 패턴)

Proxy Pattern


 

프록시


1.    원격프록시 : 원격객체에 대한 접근을 제어


2.    가상프록시 : 생성하기 힘든 자원(ex. Image)에 대한 접근을 제어


3.    보호프록시 : 접근권한이 필요한 자원에 대한 접근을 제어


 

사용 목적


실제 객체의 생성시간이 오래걸리는 경우 일을 분업하여 간단한 초기 작업을 프록시에서 하고


가장 중요한 마지막 작업에서 프록시객체는 실제 객체를 생성하고 위임한다.


 

특징


1.    프록시는 실제 서비스와 같은 이름의 메소드를 인터페이스를 사용하여 구현한다.


2.    프록시는 실제 서비스에 대한 참조 변수를 갖는다.


3.    대리자는 실제 서비스의 같은 이름을 가진 메소드를 호출하고 그 값을 클라이언트에게 돌려준다.


4.    대리자는 실제 서비스의 메소드 호출 전후에도 별도의 로직을 수행할 수 있다.



 

원격프록시


로컬 환경에 존재하며, 원격객체(JVM Heap에 있는 객체)에 대한 대변자 역할을 하는 객체


서로 다른 주소 공간에 있는 객체에 대해 마치 같은 주소 공간에 있는 것처럼 동작하게 만드는 패턴


 

가상프록시


꼭 필요로 하는 시점까지 객체의 생성을연기하고, 해당 객체가 생성된 것처럼 동작하도록 만들고 싶을 때 사용하는 패턴


 

보호프록시


객체에 대한 접근 권한을 제어하거나 객체마다 접근 권한을 달리하고 싶을 때 사용하는 패턴으로 


실객체에 대한 접근을 가로채어 중간에서 권한 점검을 수행


 

소스코드


인터페이스

public interface Image {
   
void display();
}

 

프록시

public class ProxyImage implements Image {
   
private RealImage realImage;
   
private String fileName;

   
public ProxyImage(String fileName){
       
this.fileName=fileName;
    }

   
@Override
    public void
display() {
       
if(realImage == null){
           
realImage = new RealImage(fileName);
        }
       
realImage.display();
    }
}

 

실제

public class RealImage implements Image {

   
private String fileName;

   
public RealImage(String fileName){
       
this.fileName=fileName;
       
loadFromDisk(fileName);
    }
   
private void loadFromDisk(String fileName){
       
System.out.println("Loading " + fileName);
    }
   
@Override
    public void
display() {
       
System.out.println("Displaying " + fileName);
    }
}

 

메인

public class Main {
   
public static void main(String[] args){
       
Image image = new ProxyImage("test.jpg");
       
image.display();
    }
}



결과화면




UML



Command Pattern (커맨드 패턴)

Command Pattern

 

정의

command pattern을 이용하면 요구사항을 객체로 캡슐화 하여, 요구사항을 나중에 이용할 수 있도록 메소드 이름과 매개변수 등 요구사항에 필요한 정보를 집어넣을 수 있다. 요청내역을 큐에 저장하거나 로그를 기록할 수 있으며, 작업취소 기능도 있다.

 

구성

1.    Client : Client ConcreteCommand를 생성하고 Receiver를 설정한다.

2.    Receiver : 요구사항을 수행하기 위해 어떤 일을 처리하는 객체

3.    Invoker : 명령이 있으며 execute() 메소드를 호출하여 커맨드 객체에게 특정 작업을 수행하도록 요청

4.    Command : 모든 커맨드 객체가 구현할 Interface. Receiver에게 시킬 모든 명령은 execute()메소드를 호출함으로써 수행되며, Receiver에게 특정 작업을 처리하라는 지시를 내린다.

5.    ConcreteCommand : 특정 행동과 Receiverbind한다. Invoker에서 execute()메소드 호출을 통해 요청하고 ConcreteCommand 객체에서는 Receiver에 있는 메소드를 호출함으로써 작업을 처리한다.


 

구현방법

1.    기능Class(Receiver)들을 캡슐화 한다.

2.    기능Class를 외부에 작동할 수 있는 Command (interface or class)를 추상화 및 구현한다.

3.    기능실행class(Invoker) command 타입 객체로 구현한다.

4.    기능실행class(Invoker) setter method를 구현하여 Command 타입 object를 가져오도록 한다.

5.    Invoker Object, Receiver Object, Command 타입의 Receiver Objectparameter로 하는 Object들을 생성한다.

6.    Invoker Object에서 Setter method를 호출하여 해당 commandAction Object를 등록하고, invoker에서 Command execute할 수 있는 method를 호출한다.

 

특징

request부와 execute부를 분리하고, undo, 보관, log생성이 가능하다.

장점

Receiver Command만 추가하면 dynamic하게 object 호출이 가능하다.

단점

Object 구성부가 추가되면 abstract부분부터 수정해야 한다.


 

Client 소스

public class RemoteLoader {

         public static void main(String[] args) {

                 RemoteControl remoteControl = new RemoteControl();

                 CeilingFan ceilingFan = new CeilingFan("Living Room");

                 CeilingFanHighCommand ceilingFanHigh = new CeilingFanHighCommand(ceilingFan);

                 CeilingFanOffCommand ceilingFanOff = new CeilingFanOffCommand(ceilingFan);

                 remoteControl.setCommand(2, ceilingFanHigh, ceilingFanOff);

                 System.out.println(remoteControl);

                 remoteControl.onButtonWasPushed(0);

                 remoteControl.offButtonWasPushed(0);

                 remoteControl.undoButtonWasPushed();

                 remoteControl.onButtonWasPushed(2);

                 remoteControl.offButtonWasPushed(2);

                 remoteControl.undoButtonWasPushed();

         }

}


Receiver 소스

/**
 * Receiver (천장의 FAN 작동시킨다)
 */
public class CeilingFan {
         public static final int HIGH=3;
         public static final int MEDIUM=2;
         public static final int LOW=1;
         public static final int OFF=0;
         String location;
         int speed;
         public CeilingFan(String location) {
                 // TODO Auto-generated constructor stub
                 this.location=location;
                 speed=OFF;
         }
         public void high(){
                 speed = HIGH;
         }
         public void medium(){
                 speed = MEDIUM;
         }
         public void low(){
                 speed = LOW;
         }
         public void off(){
                 speed = OFF;
         }
         public int getSpeed(){
                 return speed;
         }
}


 

Invoker

/**
 * Invoker
 */
public class RemoteControl {
         Command[] onCommands;
         Command[] offCommands;
         Command undoCommand;
         public RemoteControl() {
                 // TODO Auto-generated constructor stub
                 onCommands = new Command[7];
                 offCommands = new Command[7];
 
                 Command noCommand = new NoCommand();
                 for(int i=0; i<7; i++){
                          onCommands[i] = noCommand;
                          offCommands[i] = noCommand;
                 }
                 undoCommand = noCommand;
         }
         /**
          * @param slot
          * @param onCommand
          * @param offCommand
          * 리모컨의  slot command 넣는다.
          */
         public void setCommand(int slot, Command onCommand, Command offCommand) {
                 onCommands[slot] = onCommand;
                 offCommands[slot] = offCommand;
         }
         /**
          * @param slot
          * slot ON button 눌리면  slot OnCommand execute()메소드가 호출된다.
          */
         public void onButtonWasPushed(int slot) {
                 onCommands[slot].execute();
                 undoCommand = onCommands[slot];
         }
         public void offButtonWasPushed(int slot) {
                 offCommands[slot].execute();
                 undoCommand = offCommands[slot];
         }
         @Override
         public String toString() {
                 StringBuffer stringBuffer = new StringBuffer();
                 stringBuffer.append("\n-----Remote Control-----\n");
                 for(int i=0; i<onCommands.length; i++){
                          stringBuffer.append("[slot " + i + "] " + onCommands[i].getClass().getName()+"\n");
                 }
                 return stringBuffer.toString();
         }
         public void undoButtonWasPushed() {
                 // TODO Auto-generated method stub
                 undoCommand.undo();
         }
}


Command 소스 (fan의 속도를 높임)

/**
 *  class fan 속도를 높이고, Receiver CeilingFan 사이를 bind한다.
 */
public class CeilingFanHighCommand implements Command{
         CeilingFan ceilingFan;
         int prevSpeed;
 
         public CeilingFanHighCommand(CeilingFan ceilingFan) {
                 // TODO Auto-generated constructor stub
                 this.ceilingFan=ceilingFan;
         }
         
         /* 
          * Invoker에서 execute 호출하면 fan 속도를 높인다.
          * unDo 구현하기 위해 prevSpeed 속도 값을 저장해 둔다.
          */
         @Override
         public void execute() {
                 // TODO Auto-generated method stub
                 prevSpeed = ceilingFan.getSpeed();
                 ceilingFan.high();
         }
         
         /* 
          * prevSpeed 기준으로 speed 설정한다.
          */
         @Override
         public void undo() {
                 // TODO Auto-generated method stub
                 if(prevSpeed == CeilingFan.HIGH){
                          ceilingFan.high();
                 }else if (prevSpeed == CeilingFan.MEDIUM){
                          ceilingFan.medium();
                 }else if (prevSpeed == CeilingFan.LOW){
                          ceilingFan.low();
                 }else if (prevSpeed == CeilingFan.OFF){
                          ceilingFan.off();
                 }
         }
}


 

Command소스 (Fan의 속도를 설정)

public class CeilingFanOffCommand implements Command{
         CeilingFan ceilingFan;
         int prevSpeed;
 
         public CeilingFanOffCommand(CeilingFan ceilingFan) {
                 // TODO Auto-generated constructor stub
                 this.ceilingFan = ceilingFan;
         }
 
         @Override
         public void execute() {
                 // TODO Auto-generated method stub
                 prevSpeed = ceilingFan.getSpeed();
                 ceilingFan.off();
         }
 
         @Override
         public void undo() {
                 // TODO Auto-generated method stub
                 if(prevSpeed == CeilingFan.HIGH){
                          ceilingFan.high();
                 }else if(prevSpeed==CeilingFan.MEDIUM){
                          ceilingFan.medium();
                 }else if(prevSpeed==CeilingFan.LOW){
                          ceilingFan.low();
                 }else if(prevSpeed==CeilingFan.OFF){
                          ceilingFan.off();
                 }
         }
}

 

Command

/**
 *  class null object이다.
 * return object 없어도 client에서 null 처리하지 않아도
 * 되게   사용한다.
 */
public class NoCommand implements Command{
         @Override
         public void execute() {
                 // TODO Auto-generated method stub
 
         }
         @Override
         public void undo() {
                 // TODO Auto-generated method stub
 
         }
 
}


Interface

/**
 * 모든 command에서 구현해야 하는 interface이다.
 * 모든 command execute method 통해서 호출되며,
 *  method에서는 receiver 특정 작업을 처리하게 한다.
 */
public interface Command {
         public void execute();
         public void undo();
}

 


구현


'HeadFristDesignPattern'에 해당되는 글 2건

1 →