2

これが状況です。param 値があり、それに基づいてクラス インスタンスを返す必要があります。呼び出しごとに同じオブジェクトを返すようにします。

obj1 と obj2 は同じインターフェイスを実装します。

class Engine {
    public commonInterface getObj(int param) {
        switch(param) {
            case 1 : return obj1;
            case 2 : return obj2;
        }
    }
}

どうすればこれを達成できますか? JVM内にあることを理解しています。

4

3 に答える 3

7

これを行う 1 つの方法を次に示しますが、最適ではありません。

これは、主にオブジェクトの作成が制限されていないため、最適な方法ではありません。最適な方法であるためには、MyObjectコンストラクターが必要でprivateあり、インスタンスがそれ自体である必要があります。

ブロック内の参照を初期化することは、参照を初期化する前に他のロジックを処理できるためstatic {}、より良い方法です。これはベスト プラクティスです。inlineExceptions

しかし、これは多くの簡単で汚いコードで見られるものであり、以下の理由により、より良い解決策があるため、ほとんどが正しくありません。

class Engine {

private static final MyObject OBJ1;
private static final MyObject OBJ2;

static
{
    OBJ1 = new MyObject();
    OBJ2 = new MyObject();
}

public MyObject getObj(final int param)
{
    switch (param)
    {
        case 1:
            return Engine.OBJ1;
        case 2:
            return Engine.OBJ2;
        default:
            throw new IllegalArgumentException(String.format("%d is not a valid object id", param));
    }
}

より良い方法は次のとおりです。

これは実装を隠すため、より優れています。内部クラスを使用すると、クラスを作成できますpublicが、コンストラクターを作成し、インスタンスprivateの作成へのアクセスを制御できます。MyObject

public class Engine 
{
    private static final MyObject OBJ1;
    private static final MyObject OBJ2;

    static
    {
        OBJ1 = new MyObject1();
        OBJ2 = new MyObject2();
    }

    public MyObject getObj(final int param)
    {
        switch (param)
        {
            case 1:
                return Engine.OBJ1;
            case 2:
                return Engine.OBJ2;
            default:
                throw new IllegalArgumentException(String.format("%d is not a valid object id", param));
        }
    }

    public static class MyObject1 implements MyObject { private MyObject1() {} } 
    public static class MyObject2 implements MyObject { private MyObject2() {} } 

}

現時点で最も現代的なイディオムを使用した、最良の長期的な解決策:

このソリューションはより冗長ですが、 a のセマンティクスを適用する上で最も正確Singletonでもあります。このメソッドは、現在の JVM でのコントラクトを保証します。Singletonまた、複数のクラスローダーと複数の JVM に拡張できますがMBeanServer、別の実装に変更するだけで、他のコードを変更することなく参照をリモートで検索できます。ここでは、わかりやすくするために DI/IoC を意図的に無視しています

import javax.management.InstanceAlreadyExistsException;
import javax.management.JMX;
import javax.management.MBeanRegistrationException;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.NotCompliantMBeanException;
import javax.management.ObjectName;
import java.lang.management.ManagementFactory;

public class Engine
{
    private static final MyObject OBJ1;
    private static final MyObject OBJ2;

    static
    {
        try
        {
            final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
            final ObjectName on1 = new ObjectName("com.example:type=MyObject1");
            final ObjectName on2 = new ObjectName("com.example:type=MyObject2");
            OBJ1 = JMX.newMBeanProxy(mbs, on1, MyObject.class);
            OBJ2 = JMX.newMBeanProxy(mbs, on2, MyObject.class);
        }
        catch (MalformedObjectNameException e) { throw new RuntimeException(e); }
    }

    public MyObject getObj(final int param)
    {
        switch (param)
        {
            case 1:
                return Engine.OBJ1;
            case 2:
                return Engine.OBJ2;
            default:
                throw new IllegalArgumentException(String.format("%d is not a valid object id", param));
        }
    }

    public static class MyObject1 implements MyObjectMBean
    {
        static
        {
            try
            {
                final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
                final ObjectName on1 = new ObjectName("com.example:type=MyObject1");
                mbs.registerMBean(new MyObject1(), on1);
            }
            catch (MalformedObjectNameException e) { throw new RuntimeException(e); }
            catch (NotCompliantMBeanException e) { throw new RuntimeException(e); }
            catch (InstanceAlreadyExistsException e) { throw new RuntimeException(e); }
            catch (MBeanRegistrationException e) { throw new RuntimeException(e); }
        }

        private MyObject1() { /* your interface implementations go here */ }
    }

    public static class MyObject2 implements MyObjectMBean
    {
        static
        {
            try
            {
                final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
                final ObjectName on1 = new ObjectName("com.example:type=MyObject2");
                mbs.registerMBean(new MyObject2(), on1);
            }
            catch (MalformedObjectNameException e) { throw new RuntimeException(e); }
            catch (NotCompliantMBeanException e) { throw new RuntimeException(e); }
            catch (InstanceAlreadyExistsException e) { throw new RuntimeException(e); }
            catch (MBeanRegistrationException e) { throw new RuntimeException(e); }
        }

        private MyObject2() { /* your interface implementations go here */ }
    }

    private static interface MyObjectMBean extends MyObject { /* mbean specific methods go here */ }
    private static interface MyObject { /* your interface methods go here */ }
}

JConsoleJMX アプローチを使用することの追加の利点は、アプリケーションの実行中にこれらのインスタンスを非常に簡単に管理できることです

注:便宜上、内部クラスとして単一のファイルを使用しましたinterfacesが、問題なく独自のファイルに含めることができます。

于 2013-09-09T20:54:57.637 に答える
3

2 つのインスタンスstaticを作成し、それらを 1 回インスタンス化して、それらのみを返します。これは、 Singleton設計パターンに似ています。

class Engine {
    private static commonInterface obj1 = ...
    private static commonInterface obj2 = ...
    public commonInterface getObj(int param) {
        switch(param) {
            case 1 : return obj1;
            case 2 : return obj2;
        }
    }
}
于 2013-09-09T20:53:16.397 に答える
1

1 つの方法は、enum代わりに s を使用することです。

public enum CommonInterfaceImpl implements CommonInterface {
    Obj1,
    Obj2;

    @Override
    public void foo() {
        System.out.println("this is foo implementation");
    }
}

そして、あなたのメソッドで目的のを返しますenum:

class Engine {
    public commonInterface getObj(int param) {
        switch(param) {
            case 1 : return CommonInterfaceImpl.Obj1;
            case 2 : return CommonInterfaceImpl.Obj2;
        }
    }
}

別のアプローチは、static final Map<Integer, CommonInterface>すべてのオブジェクトを設定し、必要に応じてメソッドでそれを取得する場所を使用することです。enumこのアプローチは、事前定義されたstatic変数を使用するよりもさらに柔軟です。

class Engine {
    static final Map<Integer, CommonInterface> mapHolder = new HashMap<Integer, CommonInterface>();

    static {
        //bare example...
        //note that all this code can be replaced to load the classes dynamically
        CommonInterface obj1 = ...;
        CommonInterface obj2 = ...;
        mapHolder.put(1, obj1);
        mapHolder.put(2, obj2);
    }

    //note that the map can be filled in other methods of the Engine class...
    private void loadParameters() {
        CommonInterface obj3 = ...;
        CommonInterface obj4 = ...;
        mapHolder.put(3, obj3);
        mapHolder.put(4, obj4);
    }

    public commonInterface getObj(int param) {
        return mapHolder.get(param);
    }
}
于 2013-09-09T20:57:39.143 に答える