固定サイズの2D配列を表すD2Array
というクラスがあります。それは汎用的であることを意図しており、要素の取得、要素の設定、行全体、列全体の抽出など、非常に多くのメソッドが付属しています。
次に、D2Array
を含むMyClass
を記述します。MyClass
を適切に使用するには、内部配列の状態を操作する必要があります。簡単な解決策は、配列へのゲッターを用意し、MyClass
の外で操作してから、セッターを通じて配列に戻すことです。
(通常の代わりにTemplate<Type>
表記、私は使用しましたTemplate-Type
テンプレートパラメータを説明するために、これはちょっとした仕掛けですが、StarUMLでは、それ以外の方法で行うことはできません。)
ただし、この方法では、すべてのD2Array
をセッターに送ることができ、無効な状態の発生を防ぐために何らかの検証が必要になります。私の場合、これはすぐに高価になる可能性があり、セッターがスローする可能性があることは恐ろしく直感に反するため、これは明らかに適切な解決策ではないと思います。
カプセル化を強力に実施するという利点もある別の簡単なソリューション:MyClass
で、内部メソッドを操作するパブリックメソッドを記述します。
簡単ではない方法でのみ配列の操作を許可する必要がある場合、これは実際には問題ありません。ただし、配列の既存のメソッドの一部または全体を公開するだけの場合は、適切なメソッドに引数を転送するだけの1行の文字を書き込むことになります。 1つのクラスでこれを行う必要があることは既に鈍感に感じています。ましてや、すべて同じように異なる方法で内部配列を使用するいくつかのクラスでそれを行うことはもちろんです。
過去にさかのぼって、これが私の問題の本質だと思います。内部配列のインターフェースのサブセットのみを正確にそのまま公開し、それを行うために最小限の転送メソッドを記述しなければならず、その内容をサブセットは、内部配列を使用するクラスのニーズにも依存します。
私は次の解決策を思い付きました。これは私の要件にうまく適合しているようですが、それがアンチパターンの種類ではないかと思っています。
D2ArrayWrapper
メソッドへの転送メソッドを公に宣言および定義する、新しいクラスD2Array
(例ではダム名)を記述します。MyClass
がD2ArrayWrapper
から継承するようにします。このように、内部の2D配列が含まれており、すべての転送メソッドがすでに実装されているので、自分で書く手間が省けます。 MyClass2
も管理するD2Array
を記述したい場合、このゲインは2倍になります。D2ArrayWrapper
から継承するだけです。MyClass
の外部からアクセスできないようにするには、保護されたメンバーまたはプライベートメンバーとしてMyClass
から再宣言する必要があります。好きな理由:
嫌いな理由:
MyClass
からアクセスできるようにする配列メソッドを再宣言して再定義する代わりに、配列メソッドを再宣言しますしないMyClass
からアクセスできるようにしたい。私のDRY問題は解消されず、単純に逆転しました(C++では、単純なusing
ステートメントでうまくいきますが、Javaでは、完全な再定義が必要です)。どちらの解決策をとるべきか、今はちょっと困っています。
検証1が複雑になるため、ソリューション1は実行できません。
ソリューション2は問題ありませんが、無意味でやや上品ではありません。
ソリューション3は、手に負えなくなった事態の複雑化のように感じられ、少し考えた結果、私がやりたいことではないと確信しています。
その結果、ソリューション2を使用することを検討していますが、別の方法はありませんか?
ありがとうございます。
私が正しく理解している場合は、内部配列の一部の操作をサポートし、他の操作はサポートしないことをお勧めします。このサポートされている操作のセットが、D2ArrayWrapperが理解するのに十分一般的である場合は、インターフェイスを使用することをお勧めします。
たとえば、ユーザーが配列からセルと行を読み取れるようにしたいが、書き込みはできないようにするとします。
interface IReadOnlyD2Array<T>
{
T getCell(int row, int col);
IReadOnlyList<T> getRow(int row);
IReadOnlyList<T> getColumn(int col);
}
それはC#にありますが、同じ原則がすべてのOO言語に適用されます。次に、D2Arrayにそのインターフェイスを実装させ、代わりにそれを介してそれを返します。
private D2Array<T> _internalArray;
public IReadOnlyD2Array<T> Array => _internalArray;
一般向けにライブラリを実装している場合は、読み取り専用の性質を強制するラッパーを作成して、人々がそれをD2Arrayに強制的にキャストできないようにすることができますが、それ以外の場合は、そうしないでください。
-
関連するクラスを変更する機能がない場合、またはC++を使用していて、仮想呼び出しのオーバーヘッドを望まない場合の代替アプローチは、D2Arrayをカプセル化し、メソッドのみを公開する「ビュー」クラスを作成することです。欲しいです:
template <typename T>
class D2ArrayView
{
public:
D2ArrayView(const D2Array<T> &srcArray) : array(srcArray) { }
T getCell(int row, int col) const { return array.getCell(row,col); }
// etc ...
private:
const D2Array<T> &array;
}