問題
クライアントの動作を変更せずにオブジェクトへのアクセスを制御する必要があります。
説明
複雑なシステムを設計する場合、特定のシステムオブジェクトへの制御されたアクセスを提供する必要があることがよくあります。 これの動機は、獲得された多くの利点です。 たとえば、「バルキー」オブジェクトの遅延オンデマンド初期化、オブジェクトへの参照数のカウントなど。 など ただし、オブジェクトへの制御されたアクセスの必要性は、必ずしも利点だけに基づいているわけではありません。 原則として、現実世界のプロセスの複雑さ、コンピューティングリソースの制限により、「副」(「Surogat」)パターンの使用方法以外に設計者が選択することはありません。
「代理」パターンの考え方は、アクセスが制御されたオブジェクトと引き換えに、クライアントに別のオブジェクト(代替)を提供することです。 この場合、代替オブジェクトは元のオブジェクトと同じインターフェイスを実装するため、クライアントの動作に変更は必要ありません。 言い換えれば、クライアントは、単一のインターフェースを介して、元のオブジェクトとまったく同じように代替と対話します。 また、クライアントは、実際のオブジェクトで作業しているか、代理人で作業しているかについても仮定しません。 同時に、オブジェクトへのアクセス制御は、代替でオブジェクトへのリンクを使用することで実現されます。これにより、代替は制御されたオブジェクトに外部呼び出しを転送します。
このアプローチにより、クライアントがオブジェクトへのアクセスを暗黙的に制御できるようになります。
実用的なタスク
マインスイーパゲームを実装する際の問題を検討してください。 マイニング(Mine)および空(Empty)のセル(Cells)には、いくつかの扱いにくいグラフィックイメージがあると想定しています。 マイニングされたセルの場合-マイニング、空のセルの場合、隣接するセルの地雷の数を示す画像。 同時に、イメージ自体は各セルに保存され、作成時にインスタンス化されます。 ただし、プレーヤーは、セルが開かれた後にのみセルの画像を表示します(操作open())。 したがって、画像を保存するための共有メモリのコストを削減するために、プレーヤーがセルを開こうとする瞬間にセルをインスタンス化するのが賢明でしょう。 ただし、このアプローチはここでは適用できません。 実際、open()操作の前に、各セルはgetTop()、getLeft()を呼び出してセルの座標を取得します。 しかし、セルがまだ作成されていない場合、どの座標について話すことができますか?
プロキシパターンを使用すると、この問題を解決できます。 元のオブジェクトの代わりに、クライアントは測量士(MineProxy、EmptyProxy)を使用します。 この場合、遅延オブジェクトの初期化が可能になります。元のオブジェクトは、プロキシでopen()操作が呼び出されたときにのみ作成され、プロキシは、少なくとも元のオブジェクトまで、座標(getTop()、getLeft())オブジェクト。
クラス図
Java実装
/**
*
*/
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 .