4

私は、caseステートメントを介して同じことを何度も繰り返していたいくつかのレガシーコードをリファクタリングしています:

switch(identifier)
    case firstIdentifier: 
        (SomeCast).SetProperties(Prop1,Prop2,Prop3);
        break;
    ...
    case anotherIdentifier:
        (SomeDifferentCast).SetProperties(Prop1, Prop2, Prop3);
        break;

そこで、これができるように独自のインターフェースを作成しようとしました

(SameInterfaceCast).SetProperties(Prop1,Prop2,Prop3);

しかし、その後、一部のアイテムがすべてのプロパティを使用していないことがわかりました。それで、私はもっとこのようなことを考え始めました:

if(item is InterfaceForProp1)
    (InterfaceForProp1).SetProp1(Prop1);
if(item is InterfaceForProp2)
    (InterfaceForProp2).SetProp2(Prop2);
if(item is InterfaceForProp3)
    (InterfaceForProp3).SetProp3(Prop3);

次のようなクラスを作成できます。

public class MyClassUsesProp2And3 : InterfaceForProp2, InterfaceForProp3

ただし、このコードを過度に断片化しているため、バルーンが多すぎる可能性があります。本質的に1つのメソッドインターフェイスになることをあまり恐れてはいけないかもしれませんが、このパスを進む前に、デザインパターンが欠落していないかどうかを確認したかったのでしょうか。(私の頭に浮かんだのは、デコレータまたはコンポジットパターンだけでした)

アップデート

すべてのプロパティは一意のタイプです。

最終的に、これは依存性注入の一形態です。コードがめちゃくちゃになっていて、現在Ninjectのようなものを使用することはできませんが、最終的にはこれらの一部を取り除き、インジェクションコンテナを使用できるようになるかもしれません。現在、変数を設定するだけでなく、実行されているロジックもいくつかあります。これはすべてレガシーコードであり、少しずつクリーンアップしようとしています。

4

4 に答える 4

1

これに対する「正しい」答えがあるかどうかはわかりませんが、これが私がすることです。

class Properties {
    prop1
    prop2
    prop3
}

interface PropertySetable {
     setProperties(Properties prop);
}
public class MyClassUsesProp2And3 implements PropertySetable {
    setProperties(Properties prop) {
       //I know I need only 2 and 3
       myProp2 = prop.prop2;
       myProp3 = prop.prop3;
    }

}

関数を呼び出すときは、キャストを使用しないでください。

 someFunc(..., PropertySetable, Properties,...) {
      PropertySetable.setProperties(Properties); 
 } 

それが基本的な構造です。

プロパティをカプセル化する必要があります-プロパティをプライベートにし、関連するコンストラクターを用意します。または、ビルダーパターンを使用してプロパティを構築します...など。

于 2012-08-22T20:45:41.850 に答える
1

答えは、そもそもなぜコードをリファクタリングしたいかによると思います。

  • スイッチブロックを完全に取り除きたい場合は、3つの引数を取る1つのメソッドでインターフェイスを実装する必要があります。各クラスは、どの引数が適用され、それらの引数をどう処理するかを理解する必要があります。
  • コードの全体量を減らしたい場合は、クラス固有のプロパティ設定ロジックを追加することが、元のswitchステートメントよりも少ないコードであるかどうかはわかりません。
  • エディターのコード補完機能を利用して、正しい数のプロパティ/引数を持つ正しいメソッドを挿入する場合は、各クラスに正しいメソッドを実装し、インターフェイスを完全に回避します
于 2012-08-22T21:41:31.850 に答える
1

訪問者パターンは、switchステートメントとタイプキャストに直面した場合の標準的なソリューションです。各ケースのコードは、ビジタークラスの個別のメソッドに入ります。また、クラスはそれぞれ1つのインターフェース(accept訪問者を受け入れるメソッド)のみを実装します。あなたは今あなたが持っているより多くのコードで終わるでしょう、しかしそれはずっときれいに読まれるでしょう。

于 2012-08-23T05:52:41.167 に答える
1

基本的に、アクター(setPropメソッドを使用して入力)を同じタイプ'Actor'にし、プロパティ(prop1 ... n)を同じタイプ'Prop'にします。これにより、コードが次のように削減されます

actor.setProp(prop)

instanceOfの使用を避けたい場合、私が考えることができる唯一の方法は、Visitorパターンを使用して、「Prop」をビジターにすることです。また、テンプレートメソッドを使用して生活を楽にします。Javaでは、次のようになります(2種類の実際のプロップの場合)。

class Actor {

    protected void set(Prop1 p1) {
        // Template method, do nothing
    }

    protected void set(Prop2 p2) {
        // Template method, do nothing
    }

    public void setProp(Prop p) {
        p.visit(this);
    }

    public interface Prop {
        void visit(Actor a);
    }

    public static Prop makeComposite(final Prop...props ) {
        return new Prop() {

            @Override
            public void visit(final Actor a) {
                for (final Prop p : props) {
                    p.visit(a);
                }
            }
        };
    }

    public static class Prop1 implements Prop {
        public void visit(Actor a) {
            a.set(this);
        }
    }

    public static class Prop2 implements Prop {
        public void visit(Actor a) {
            a.set(this);
        }
    }
}

これにより、次のようなことができます。

    ConcreteActor a = new ConcreteActor();
    Prop p = Actor.makeComposite(new ConcreteProp1(42), new ConcreteProp2(-5));
    a.setProp(p);

...これはとてもいいです!

于 2012-08-23T07:23:01.360 に答える