次の(アンチ)パターンの名前は何ですか?その長所と短所は何ですか?


28

過去数ヶ月間、私は次のテクニック/パターンで数回つまずきました。しかし、特定の名前を見つけることはできないようです。また、その長所と短所を100%確信しています。

パターンは次のとおりです。

Javaインターフェース内では、一般的なメソッドのセットが通常どおり定義されます。ただし、内部クラスを使用すると、デフォルトのインスタンスがインターフェースを介してリークされます。

public interface Vehicle {
    public void accelerate();
    public void decelerate();

    public static class Default {
         public static Vehicle getInstance() {
             return new Car(); // or use Spring to retrieve an instance
         }
    }
 }

私にとって、最大の利点は、開発者がインターフェイスについてのみ知る必要があり、実装についてではなく、インスタンスをすぐに作成したい場合などです。

 Vehicle someVehicle = Vehicle.Default.getInstance();
 someVehicle.accelerate();

さらに、構成に応じてインスタンスを動的に提供するために、Springと共にこの手法が使用されているのを見てきました。この点で、これもモジュール化に役立つようです。

それにもかかわらず、インターフェイスを実装の1つと結合するため、これがインターフェイスの誤用であるという感覚を揺るがすことはできません。(依存性反転の原理など。)誰もがこの技術がどのように呼ばれるか、そしてその長所と短所を私に説明してもらえますか?

更新:

しばらく検討した後、次のシングルトンバージョンのパターンがはるかに頻繁に使用されていることを再確認しました。このバージョンでは、パブリックの静的インスタンスは、(フィールドが最終であるために)1回だけ初期化されるインターフェイスを介して公開されます。さらに、インスタンスはほとんどの場合、Springまたは実装からインターフェイスを分離する汎用ファクトリーを使用して取得されます。

public interface Vehicle {
      public void accelerate();
      public void decelerate();

      public static class Default {
           public static final Vehicle INSTANCE = getInstance();

           private static Vehicle getInstance() {
                return new Car(); // or use Spring/factory here
           }
      }
 }

 // Which allows to retrieve a singleton instance using...
 Vehicle someVehicle = Vehicle.Default.INSTANCE;

簡単に言うと、これはカスタムシングルトン/ファクトリパターンであるように思われます。これにより、基本的に、インターフェイスを通じてインスタンスまたはシングルトンを公開できます。欠点については、以下の回答とコメントでいくつかの名前が付けられています。これまでのところ、利点はその利便性にあるようです。


ある種のシングルトンパターン?
ブライアンチェン

インターフェースがその実装を「知らない」ことは正しいと思います。おそらくVehicle.Default、ファクトリクラスとしてパッケージ名前空間に移動する必要がありますVehicleFactory
8

7
ちなみにVehicle.Default.getInstance() != Vehicle.Default.getInstance()
コンラッド・モラウスキー

20
ここでのアンチパターンは、動物アナロジーのアンチパターンに密接に関連するカーアナロジーのアンチパターンを使用することです。ほとんどのソフトウェアには車輪や脚がありません。
ピーターB

@PieterB::-))))あなたは私の一日を作りました!
Doc Brown

回答:


24

Default.getInstance私見は、ファクトリメソッドの非常に特定の形式であり、シングルトンパターンから取られた命名規則と混同されています(しかし、後者の実装ではありません)。現在のフォームでは、これは「単一の責任原則」に違反しています。これは、インターフェイス(クラスAPIを宣言する目的を既に果たしている)がデフォルトインスタンスを提供する追加の責任を負うためです。VehicleFactoryクラス。

この構築物によって引き起こされる主な問題は、それが間に環状の依存を誘導することであるVehicleCar。たとえば、現在のフォームではVehicle、あるライブラリとCar別のライブラリに配置することはできません。別のファクトリクラスを使用してDefault.getInstanceメソッドを配置すると、その問題が解決します。また、シングルトンに関連する混乱を防ぐために、そのメソッドに別の名前を付けることをお勧めします。結果は次のようになります

VehicleFactory.createDefaultInstance()


ご回答有難うございます!この特定の例がSRPの違反であることに同意します。ただし、実装が動的に取得される場合、それが依然として違反であるかどうかはわかりません。たとえば、Spring (または同様のフレームワーク)を使用して、構成ファイルなどで定義された特定のインスタンスを取得します。
ジェローム

1
@Jérôme:私見名前の入れ子になっていないクラスVehicleFactoryVehicle.Default、特に誤解を招く「getInstance」メソッドで、入れ子になったコンストラクトよりも一般的です。Springを使用することで周期的な依存関係を回避することは可能ですが、私は常識のために最初のバリエーションを個人的に好みます。さらに、ファクトリを別のコンポーネントに移動し、後で実装をSpringなどなしで動作するように変更するオプションがまだあります。
Doc Brown

多くの場合、クラスではなくインターフェイスを使用する理由は、インターフェイスの実装を必要とするコードが他の目的を持つクラスを使用できるようにするためです。デフォルトの実装クラスが、「通常」の方法でインターフェースを実装するものを単に必要とするコードのすべてのニーズを満たすことができる場合、インスタンスを作成する手段を指定することは、インターフェースにとって有用なことです。
supercat

CarがVehicleの非常に汎用的な標準実装である場合、これはSRPの違反ではありません。Googleがautodrive()メソッドを追加する場合など、車両には変更する理由が1つしかありません。非常に汎用的なCarは、NotImplementedExceptionをスローするなどして、そのメソッドを実装するように変更する必要がありますが、Vehicleで変更する追加の理由はありません
user949300 14年

@ user949300:SRPは「数学的に証明可能な」概念ではありません。また、ソフトウェア設計の決定が常に「白黒」であるとは限りません。元のコードはそれほど悪くないので、もちろん運用コードで使用することはできません。また、OPが「更新」で自分で指摘しているように、利便性が循環依存性を上回る場合があります。それで、私の答えを読んでください。「別のファクトリークラスを使用することはあなたにより良いサービスを提供しないならば、考慮してください」。また、著者が答えを出した後、著者が元の質問を少し変更したことに注意してください。
Doc Brown 14年

3

これは、Null Objectパターンのように見えます。

しかし、それCarはクラスの実装方法に大きく依存します。「中立」な方法で実装されている場合、それは間違いなくNullオブジェクトです。つまり、インターフェイスのすべてのnullチェックを削除し、の各出現の代わりにこのクラスのインスタンスを配置できる場合、nullコードは引き続き正しく動作する必要があります。

また、このパターンであれば、インターフェイス自体とnullオブジェクトの実装との間に密結合が生じる問題はありません。nullオブジェクトは、上記のインターフェイスが使用されるすべての場所に存在できるためです。


2
こんにちは、答えてくれてありがとう。私の場合、これは「Null Object」パターンの実装に使用されていなかったと確信していますが、興味深い説明です。
ジェローム
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.