📜 ⬆️ ⬇️

Design Pattern "Deputy" / "Proxy"

Read the description of other patterns.

Problem


It is necessary to control access to the object, without changing the behavior of the client.

Description


When designing complex systems, quite often there is a need to provide controlled access to certain objects of the system. The motivation for this is a number of benefits acquired. Such as lazy initialization on demand for “bulky” objects, counting the number of references to an object, etc. etc. However, the need for controlled access to an object is not always based only on benefits. As a rule, the complexity of the real world processes, the limitations of computational resources simply do not leave the designer a choice, rather than how to use the “Deputy” (“Surogat”) pattern.

The idea of ​​the “Deputy” pattern is to provide the client with another object (deputy), instead of the object with controlled access. At the same time, the deputy object implements the same interface as the original object, as a result, the client's behavior does not require changes. In other words, the client interacts with the Deputy exactly as with the original object through a single interface. The client also does not make assumptions about whether he works with a real object or his deputy. Control of access to the object, in this case, is achieved by using the reference to it in the Deputy, thanks to which the Deputy redirects external calls to the controlled object, possibly accompanying them with additional operations.
')
This approach allows implicit for the client to control access to the object.

Practical task


Consider the task of implementing the game “Minesweeper”. We assume that for cells (Cell), which are mined (Mine) and empty (Empty), there are some cumbersome graphic images. For a mined cell, a mine; for an empty cell, an image with the number of mines in the adjacent cells. In this case, the image itself is stored in each cell and instantiated at the time of its creation. The player sees the cell image only after it is opened (operation open ()). Therefore, it would be wise to instantiate the cells at the moment when the player tries to open them in order to reduce the cost of shared memory for storing images. However, this approach can not be applied here. The fact is that before the open () operation, each cell is invoked with getTop (), getLeft () operations to get the coordinates of the cell. But if the cell is not yet created, what coordinates can we talk about?

Using the proxy pattern solves this problem. Instead of the original objects, the client will use their surveyors (MineProxy, EmptyProxy). At the same time, lazy initialization of cells becomes possible, since the original object is created only when the proxy open () operation is called and the proxy coordinates get requests (getTop (), getLeft ()) responds independently, at least until the original object.

Class diagram




Java implementation


/**
*
*/
public abstract class Cell {
public static final int OPENED = 0;
public static final int CLOSED = 1;

protected int status;

protected int left, top;

public Cell( int left, int top) {
super();

this .left = left;
this .top = top;
this .status = Cell.CLOSED;
}

/**
* . ,
* . , , .
*/
public void open() {
this .status = Cell.OPENED;
}

public int getLeft() {
return left;
}

public int getTop() {
return top;
}

public int getStatus() {
return status;
}

/**
* , .
*/
public abstract int getPoints();
}

/**
* ,
*/
public class Empty extends Cell {

public Empty( int left, int top) {
super(left, top);

// .
}

@Override
public int getPoints() {
return 10; // 10
}
}

/**
* , .
*/
public class Mine extends Cell {

public Mine( int left, int top) {
super(left, top);

// c
}

@Override
public int getPoints() {
return 100; // 100
}
}

/**
*
*/
public class EmptyProxy extends Cell {
private Empty proxy; //

public EmptyProxy( int left, int top) {
super(left, top);
this .proxy = null ;
}

/**
*
*/
@Override
public void open() {
if (proxy == null ) {
proxy = new Empty(left, top);
}

proxy.open();
}

@Override
public int getLeft() {
if (proxy == null ) {
return left;
} else {
return proxy.getLeft();
}

}

@Override
public int getTop() {
if (proxy == null ) {
return top;
} else {
return proxy.getTop();
}
}

@Override
public int getStatus() {
if (proxy == null ) {
return status;
} else {
return proxy.getStatus();
}
}

@Override
public int getPoints() {
if (proxy == null ) {
return 10;
} else {
return proxy.getPoints();
}
}
}

/**
*
*/
public class MineProxy extends Cell {
private Mine proxy;

public MineProxy( int left, int top) {
super(left, top);

this .proxy = null ;
}

/**
*
*/
@Override
public void open() {
if (proxy == null ) {
proxy = new Mine(left, top);
}

proxy.open();
}

@Override
public int getLeft() {
if (proxy == null ) {
return left;
} else {
return proxy.getLeft();
}

}

@Override
public int getTop() {
if (proxy == null ) {
return top;
} else {
return proxy.getTop();
}
}

@Override
public int getStatus() {
if (proxy == null ) {
return status;
} else {
return proxy.getStatus();
}
}

@Override
public int getPoints() {
if (proxy == null ) {
return 100;
} else {
return proxy.getPoints();
}
}
}

/**
*
*/
public class Main {
public static void main( String [] args) {
Cell cells[][] = new Cell[10][10];

for ( int i=0; i<10; i++) {
for ( int j=0; j<10; j++) {

if (i+j % 2 == 0) {
cells[i][j] = new MineProxy(i, j);
} else {
cells[i][j] = new EmptyProxy(i, j);
}
}
}

for ( int i=0; i<10; i++) {
for ( int j=0; j<10; j++) {
cells[i][j].open();
}
}
}
}

* This source code was highlighted with Source Code Highlighter .

Source: https://habr.com/ru/post/88722/


All Articles