2

这就是这种情况,我有一个参数值,基于此我需要返回一个类实例。我希望在每次调用时都返回相同的对象。

obj1 和 obj2 实现相同的接口。

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

我如何实现这一目标?我知道它在JVM中。

4

3 回答 3

7

这是一种方法,但它不是最佳的:

这不是最好的方法,主要是因为对象的创建不受限制,因为它是最佳的MyObject构造函数需要private并且实例需要在其自身上。

初始化static {}块中的引用是一种更好的做法,inline因为您可以Exceptions在初始化引用之前处理其他逻辑,这是一种最佳做法

但这是你在很多快速而肮脏的代码中看到的,这些代码大多是不正确的,因为下面的原因在更好的解决方案中。

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的。该方法保证Singleton合约在当前 JVM 中。它还可以扩展到多个类加载器和多个 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 */ }
}

使用 JMX 方法的额外好处是您可以JConsole非常轻松地管理这些实例,而在应用程序运行时,您可以免费获得!

注意:为了方便起见,我使用了带有 as 内部类的单个文件interfaces,它们可以在自己的文件中没有问题。

于 2013-09-09T20:54:57.637 回答
3

制作两个实例static,并实例化一次,然后只返回它们。这类似于单例设计模式。

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

一种方法可以使用enums 代替:

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这种方法比拥有s 个预定义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 回答