3

グローバル変数から構成の一部を取得するいくつかのクラスに取り組んでいます。

class MyClass {
    public void MyClass(Hashtable<String, String> params) {
        this.foo = GlobalClass.GLOBALVAR.get("foo");
        this.bar = GlobalClass.GLOBALVAR.get("bar");
        this.params = params;
    }
}

これにはいくつかの理由があります。GLOBALVAR はデータベースと通信していくつかの変数を取得するため、単体テストを作成するのが非常に難しくなります。もう 1 つの問題は、MyClass から継承するクラスが多数 (数十個) あるため、コンストラクターのシグネチャを簡単に変更できないことです。

私の現在の解決策は、 と の追加のデフォルト コンストラクターとセッター メソッドを作成するparamsことfooですbar

class MyClass {
     // Other code still here for backwards compatibility.
     public void MyClass() {
         // Do nothing much.
     }
     public void setParams(Hashtable<String, String> params) {
         this.params = params;
     }
     public void setFoo(Foo foo) {
         this.foo = foo;
     }
     public void setBar(Bar bar) {
         this.bar = bar;
     }
}

私がやった方法以外に、これをリファクタリングする良い方法についてのアイデアはありますか? 私の他の考えは、ファクトリ メソッドを使用することですが、ポリモーフィックな置換の問題に遭遇するのではないかと心配しています。

4

6 に答える 6

3

私は次のことから始めると思います。既存のコードを変更せずに機能させ、可能な限り新しいコンストラクターをサブクラスに追加できるようにします。すべてのサブクラスに新しいコンストラクターがあり、古いコンストラクターへの呼び出しがすべてなくなったら、GlobalClass とそれを使用するコンストラクターを取り除くことができます。また、うまくいけば、GLOBALVAR (私のコードの Car クラス) のクリーンアップに取り組むこともできます。

import java.util.Hashtable;


class MyClass
{
    private final Foo foo;
    private final Bar bar;
    private final Hashtable<String, String> params;

    public MyClass(final Hashtable<String, String> params)
    {
        this(params, GlobalClass.GLOBALVAR);
    }

    // added constructor
    public MyClass(final Hashtable<String, String> params, 
                   final FooBar fooBar)
    {
        this.foo    = fooBar.getFoo();
        this.bar    = fooBar.getBar();
        this.params = params;
    }
}

class MySubClass
    extends MyClass
{
    public MySubClass(final Hashtable<String, String> params)
    {
        super(params);
    }

    // added constructor
    public MySubClass(final Hashtable<String, String> params, 
                      final FooBar fooBar)
    {
        super(params, fooBar);
    }
}

// unchanged
class GlobalClass
{
    public static Car GLOBALVAR;
}

// added interface
interface FooBar
{
    Foo getFoo();
    Bar getBar();
}

class Car
    // added implements
    implements FooBar
{
    private Foo foo = new Foo();
    private Bar bar = new Bar();

    public Object get(final String name)
    {
        if(name.equals("foo"))
        {
            return (foo);
        }

        if(name.equals("bar"))
        {
            return (bar);
        }

        throw new Error();
    }

    // added method
    public Foo getFoo()
    {
        return ((Foo)get("foo"));
    }

    // added method
    public Bar getBar()
    {
        return ((Bar)get("bar"));
    }
}

// unchanged
class Foo
{
}

// unchanged
class Bar
{
}
于 2009-04-07T17:58:53.210 に答える
1

アプローチのわずかなバリエーションは、クラスに GLOBALVAR タイプのオブジェクトを持ち、実際のグローバルの代わりにそれを使用することです (そのリファクタリングは単純な検索/置換である必要があります)。新しい変数を実際のグローバル変数にデフォルト設定し、テスト用のオーバーライドを提供できます。

于 2009-04-07T17:19:50.807 に答える
0

クラス階層を自由に変更できると述べたので。

  • ベース MyClass ctor を変更して、params、foo、bar の 3 つのパラメーターを受け取ります。GlobalVar 参照をコメントアウトし、渡された値を単純にキャッシュします
  • コンパイル..これにより、一連のコンパイルエラーが発生するはずです-1つのパラメーターを受け取るctorはありません。
  • GlobalVar.get("foo") と GlobalVar.get("bar") で渡すようにそれぞれを修正します。ビルドしてください。
  • Refine: 遅延読み込みと foo と bar の値のキャッシュにより、DB へのヒットを最小限に抑えます。GlobalVar のいくつかのプロパティを介して公開します。
于 2009-04-07T18:31:02.180 に答える