問題
システムの最下位レベルのオブジェクトを設計すると、最適な柔軟性が得られますが、メモリとパフォーマンスの許容できないコストが伴います。
説明
すでに述べたように、多数の小さく単純なオブジェクトから複雑な複合オブジェクトを構築することを目的としたソフトウェアシステムが多数あります。 同時に、このようなシステムの柔軟性と汎用性は、ユーザーにツールとプリミティブの完全なセットを提供することにより実現されます。 このコンテキストでは、プリミティブは基本オブジェクトであり、その後コンポジットが構築されることを理解することが重要です。 さらに、オブジェクトがプリミティブと見なされるレベルは、実際、このシステムの適用性と有効性を決定します。 ただし、最低レベルの抽象化までシステムを設計できるとは限りません。 メモリコストと低いシステムパフォーマンスは、直接的なアプローチでは、これを許可しません。 したがって、そのようなシステムを設計するときは、「適応」パターンがよく使用されます。
アダプティブは分離を使用して、多くの小さなオブジェクトを効果的にサポートします。
パターンの主なアイデアは、オブジェクトの内部状態と外部状態の違いです。 外部状態は、特定のコンテキストで適応を使用してクライアントによって伝達されます。 内部状態はアダプテーションに直接保存され、それらを分離できます。 分離とは、同じ適応性を持つ複数のクライアントの同時作業の可能性を意味します。 したがって、日和見主義者には共有と非共有の2種類があります。 明らかに、日和見主義者と協力しているクライアントは、彼らの性質について仮定をせず、与えられた文脈でのみそれらを使用します。 したがって、クライアントには、フィッティングを分離するための透過的なメカニズムを提供する必要があります。
アダプティブは、異なるコンテキストで同時に使用できます。 まるで彼が自分の使用状況に「適応」しているようです。 同時に、クライアントは、異なるオブジェクトで作業しているという印象を持っています。 実際には、それはまったく同じ日和見主義者です。
上記のすべてを要約すると、日和見主義者はサブジェクト領域のエンティティをモデル化することに注意する必要があります。その数は実際のオブジェクトで表現するには多すぎます。
実用的なタスク
ベクトルエディターの設計作業を検討してください。 さらに、エディターの最大限の柔軟性を得るには、最低レベル-基本プリミティブ-ポイントまで設計する必要があります。 明らかに、直接的なアプローチでは、1つの図面に膨大な数のポイントが存在する可能性がありますが、編集者が作業してメモリに保存するのは容易ではありません。 したがって、「Adaptive」パターンを使用してエディターを設計します。
ベクトルエディターに、限られたプリミティブセット(正方形、円、点、および画像)の操作方法を知らせます。 これらのプリミティブはすべて日和見主義者です。 さらに、その複合的な性質のため、画像のみが共有適応ではありません。 この場合の画像は「リンカー」パターンの例であることに注意してください。 残りのプリミティブは、内部状態に基づいて分割する必要があります。 正方形の場合-辺のサイズ(高さ、幅)、円の場合-半径(半径)。 ポイントは、共有適応ですが、そのレンダリングに必要なすべての情報がクライアントによっていわゆるクライアントに送信されるという事実を考慮して、内部状態を持ちません。 描画のコンテキスト(コンテキスト)。
クラス図
この例では、工場-PrimitiveFactoryが日和見主義者の分離のメカニズムを実装するために使用されました。 オブジェクトを分離するためのメカニズムはファクトリーだけではありません。 場合によっては、クラスの静的メンバーを省くことができます。
Java実装
/*
*
*/
public interface Primitive {
/*
*
*/
public void draw(Context context);
}
/*
* - . -
*/
public class Circle implements Primitive {
private int radius;
public Circle( int radius) {
this .radius = radius;
}
@Override
public void draw(Context context) { }
}
/*
* - .
* - , .
*/
public class Square implements Primitive {
private int height, width;
public Square( int height, int width) {
this .height = height;
this .width = width;
}
@Override
public void draw(Context context) { }
}
/*
* -
*/
public class Point implements Primitive {
@Override
public void draw(Context context) { }
}
import java.util.Arrays;
import java.util.LinkedList;
import java.util. List ;
/*
* - .
*/
public class Picture implements Primitive {
private List <Primitive> childrens;
public Picture(Primitive ...primitives) {
this .childrens = new LinkedList<Primitive>();
this .childrens.addAll(Arrays.asList(primitives));
}
@Override
public void draw(Context context) {
for (Primitive p: childrens) {
p.draw(context);
}
}
}
import java.awt.Color;
/*
* ,
*/
public final class Context {
public final int x;
public final int y;
public final Color color;
public Context( int x, int y, Color collor) {
this .x = x;
this .y = y;
this .color = collor;
}
}
import java.util.HashMap;
import java.util.Map;
/*
* .
* .
*
*/
public abstract class PrimitiveFactory {
private static Point onePoint;
private static Map<Integer, Circle> circles;
private static Map<Integer, Square> squares;
static {
circles = new HashMap<Integer, Circle>();
squares = new HashMap<Integer, Square>();
}
public static synchronized Picture createPicture(Primitive ... childrens) {
return new Picture(childrens);
}
public static synchronized Circle createCircle( int radius) {
if (circles. get (radius) == null ) {
circles.put(radius, new Circle(radius));
}
return circles. get (radius);
}
public static synchronized Square createSquare( int height, int width) {
if (squares. get (height*10+width) == null ) {
squares.put(height*10+width, new Square(height, width));
}
return squares. get (height*10+width);
}
public static synchronized Point createPoint() {
if (onePoint == null ) {
onePoint = new Point();
}
return onePoint;
}
}
import java.awt.Color;
//
public class Main {
public static void main( String [] args) {
Primitive[] primitives = {
PrimitiveFactory.createPoint(),
PrimitiveFactory.createCircle(10),
PrimitiveFactory.createSquare(20, 30),
PrimitiveFactory.createCircle(20),
PrimitiveFactory.createCircle(20),
PrimitiveFactory.createPoint(),
PrimitiveFactory.createSquare(20, 40),
};
Picture picture = PrimitiveFactory.createPicture(primitives);
Context context = new Context(10, 20, Color.BLUE);
picture.draw(context);
}
}
* This source code was highlighted with Source Code Highlighter .
このパターンの適用可能性は、まず、システムオブジェクトの内部状態と外部状態が明確に識別されるかどうかによって決まることを理解することが重要です。