这种情况,我有一个param值,基于此我需要返回一个类实例。我想在每次调用时返回相同的对象。
obj1和obj2实现相同的接口。
class Engine {
public commonInterface getObj(int param) {
switch(param) {
case 1 : return obj1;
case 2 : return obj2;
}
}
}
我如何实现这一目标?我理解它在JVM中。
答案 0 :(得分:6)
这不是最好的方法,主要是因为对象的创建不受限制,因为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() {} }
}
此解决方案更加详细,但在执行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 */ }
}
使用JMX方法的额外好处是,您可以非常轻松地使用JConsole
管理这些实例,而在应用程序运行时,您可以获得 free !
注意:我使用一个interfaces
作为内部类的文件作为权宜之计,它们可以在他们自己的文件中没有问题。
答案 1 :(得分:3)
创建两个实例static
,并将它们实例化一次,并仅返回它们。这类似于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;
}
}
}
答案 2 :(得分:1)
一种方法是使用enum
代替:
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);
}
}