複合設計パターン

他のパターン説明を読んでください

問題


ツリー構造のリーフおよび複合要素への一貫したアクセスを顧客に提供します。

説明


オブジェクトのツリー構造が何らかの方法で適用されるソフトウェアシステムが多数あります。 ほとんどの場合、これらはすべて、 小さなもの(シート)から大きなもの(複合)を組み立てることができるデザイナー/エディターの種類です。 同時に、クライアントは大小両方を同じものとして解釈し、システムはそれぞれ複合オブジェクトとシートオブジェクトを区別する必要があります。

デザイナープログラムだけがこのパターンを使用するわけではありません(ただし、使用することを望みます)。 このようなツリー構造の顕著な例は、ユーザーインターフェイス(GUI)です。 実際、一般的なユーザーインターフェイスウィンドウは、よりシンプルなウィジェットのコンテナです。パネル、ボタン、水場など、さらにパネルはコンテナオブジェクトなど、基本的なシートオブジェクトまでです。 このコンテキストでのこのパターンの使用の顕著な例は、Swingインターフェースレンダリングライブラリ(javax.swing.JComponentクラスを意味します)です。

したがって、提起された問題に戻ります-クライアントにツリー構造のリーフおよび複合要素への均一なインターフェースを提供します。 明らかに、この問題を解決するには、基本オブジェクトと複合オブジェクトの両方を記述する共通インターフェースを確立する必要があります。 また、 インターフェイスは複合オブジェクトも記述します;コンテナメソッドを追加する必要があります-コンテナからオブジェクトを追加、削除、追加、削除、取得します。 さらに、これらのメソッドは同じ共通インターフェースによってパラメーター化される必要があります。 したがって、基本オブジェクトだけでなく、他のコンテナもコンテナに追加することが自動的に可能になります。

ツリー構造のすべてのオブジェクト(リーフおよび複合)はこの統一されたインターフェイスを実装する必要があり、複合オブジェクトは追加、削除、取得操作をオーバーライドし、リーフオブジェクトは単にそれらを無視します。

実用的なタスク


「リンカー」パターンを使用して、式の最も単純な加算器を作成しましょう。 加算器は式の解析に関与するべきではなく、式のより便利な計算のためにツリー構造を記述して実装するだけです。

具体的には、コンストラクターまたはユーザーインターフェイスを使用した古典的な例を取り上げなかったため、読者はパターンの狭い方向についての印象をまったく持ちません。

クラス図


まず、いくつかのコメント。 この例では、コンテナーの概念をわずかに異なる方法で解釈します。 コンテナの古典的な概念をサブジェクトエリアに投影した、つまり式の計算だと言ってみましょう。 私の「コンテナ」の動作は、従来のものとは多少異なります。 remove()メソッドの代わりに、SubExpressionにはsub()メソッドがあります。これは実際にはコンテナーからの削除を行いますが、独自の方法でのみ実行します。 これはまだ加算器であるという事実のために、add()のようなsub()メソッドは、コンテナに部分式を追加しますが、符号が反対なので、減算を実装します。



チャートを検討してください。 SubExpressionインターフェイスは、ツリー構造のすべてのオブジェクトの統一されたインターフェイスを記述します。ちなみに、これらは、整数(IntegetValue)、実数(FloatValue)、および式(Expression)という多数ではありません。 明らかに、それらはすべての数値(シートオブジェクトとコンテナメソッドを実装しているわけではありません)、および式はまったく反対です-コンテナです。

Java実装


実装にはFloatValueクラスコードはありません
//
public interface SubExpression {

public Number value ();

public void add(SubExpression expr);
public void sub(SubExpression expr);
public SubExpression getSubExpression( int index);
}

// -
public class IntegerValue implements SubExpression {

private Integer value ;

public IntegerValue(Integer value ) {
this . value = value ;
}

@Override
public void add(SubExpression expr) {
throw new UnsupportedOperationException();
}

@Override
public SubExpression getSubExpression( int index) {
throw new UnsupportedOperationException();
}

@Override
public void sub(SubExpression expr) {
throw new UnsupportedOperationException();
}

@Override
public Number value () {
return value ;
}
}

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

// -
public class Expression implements SubExpression {

private List <SubExpression> exprs;

public Expression(SubExpression ... exprs) {
this .exprs = new ArrayList <SubExpression>();
for (SubExpression expr: exprs) {
this .exprs.add(expr);
}
}

@Override
public void add(SubExpression expr) {
exprs.add(expr);
}

@Override
public void sub(SubExpression expr) {
if (expr instanceof IntegerValue) {
exprs.add( new IntegerValue(-1*expr. value ().intValue()));
} else {
exprs.add( new FloatValue(-1*expr. value ().floatValue()));
}

}

@Override
public SubExpression getSubExpression( int index) {
return exprs. get (index);
}

@Override
public Number value () {
Number result = new Float(0);

for (SubExpression expr: exprs) {
result = result.floatValue() + expr. value ().floatValue();
}

return result;
}
}

//
public class Main {

public static void main( String [] args) {
// - 20 - (5-2) - (11+6)
// 20 - a - b
SubExpression expr = new Expression();

SubExpression a = new Expression( new IntegerValue(5), new IntegerValue(-2));
SubExpression b = new Expression( new IntegerValue(11), new IntegerValue(6));

expr.add( new IntegerValue(20));
expr.sub(a);
expr.sub(b);

System. out .println(expr. value ());
}
}

* This source code was highlighted with Source Code Highlighter .


パターンのアイデアを皆さんに伝えることができたと思います。

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


All Articles