web-dev-qa-db-ja.com

階層ツリーを拡張する正しい方法

現在Javaで実装される次のツリーがあります。 enter image description here

私の問題は次のとおりです。

  • 5つのクラスすべてを継承できないため、管理者がツリーの両方のブランチからすべての層4のロジックを持つ必要があるという事実に対処するにはどうすればよいですか?
  • ティア4と匿名クラスの外では、Javaの制限のために複数の抽象をそれぞれティア4まで拡張することができないため、ツリーをリファクタリングして残りをインスタンス化しないでください。 (私はそれらのコンストラクターをプライベートに設定してこれで完了できますが、ツリーの設計上の欠陥を回避するための安価なハックのように感じます)。
3
Leon

ここでの問題は、あなたが継承とのこの種の関係を表現するように誤解されてきたことです。あなたは何も悪いことをしていない、この問題は継承の問題の典型であり、なぜそれが一般に合成に向いていないのか。

継承に構成を優先

この問題には多くのアプローチがありますが、以下は最も単純なものとして私に際立っているものです:

まず、階層とは異なり、ユーザークラスがあり、これはシステムユーザーを表します。

明らかに、これらはクイックレイアウトであり、プロパティをゲッター、セッターなどで置き換えます。

interface HasSessionId
{ 
    ID;
}

interface CanCheckPermission
{
    HasPermissionTo(permission); 
}

class AnnoUser implements CanCheckPermission, HasSessionId
{
    ID;
}


class RegisterUser implements CanCheckPermission, HasSessionId
{
     ID;  
     UserName;
     FirstName;
     LastName;
     Login; //Sometimes it is helpful to separate the login into a a different concept to make impersonation easier, ect, you may or may not need this in your system.
}

次に、システムの役割があります。これはユーザーとはまったく異なります。それらが持つ可能性のある一般的な動作またはプロパティは、インターフェイスにあります。インターフェイスは最小限の機能のみを実装し、実装なしの基本クラスと見なすべきではありません。彼らはシステムロールができることを表現するだけです。

interface IsAUser
{
    User;
}

interface CanBuy
{
     Buy(product);
}

私たちの個々のシステムロールは、これらのインターフェイスを実装して利用可能な機能を表現できるようになり、必要に応じて自由に異なる方法で処理を行うことができますが、購入ユーティリティが登場する共通の振る舞いを利用する場合があります。

class BuyingUtility
{
   //static stuff is generally bad, but this is the closest Java has to functions. Avoid static fields as much as possible
   static Buy(product, IsAUser) { /*buy logic*/ }
}

class Admin implements IsAUser, CanBuy, CanSell
{
     User;
     Buy(product)
     {
           BuyingUtility.Buy(product, this);
     }
}

class BuyerManager implements IsAUser, CanBuy
{
     User;
     Buy(product)
     {
           BuyingUtility.Buy(product, this);
     }
}
3
TheCatWhisperer

機能が相互に排他的(購入者対販売者)であり、累積的(管理者)であるいくつかのクラスを作成したという事実は、(Javaで作業する場合)すべてがclassesではないことを証明します。したがって、これらのさまざまなエンティティを表すには、多少複雑な別のモデルを見つける必要があります。

一般的な選択肢は、のみさまざまな機能を保持するクラスを作成し、これらから実際のエンティティを表すオブジェクトを構成することです。 mix-insdecoratorstraitsまたはfacetsを検索すると、さまざまな確立されたパターンのドキュメントが表示されますこの目的のために。

2
Kilian Foth