【问题标题】:Java singleton enum programmed to the interface?Java单例枚举编程到接口?
【发布时间】:2016-03-17 10:53:35
【问题描述】:

这是我在这里的第一篇文章,所以我会尽量准确。这是一个大学项目,我们必须在我们单独制作的 OO 架构之上创建一个鱼缸模拟。我正在探索单例的用途并发现它们非常有用,但是在线阅读我目前实现它的方式并不是线程安全的。

我目前实现的方式(认为是惰性方法)注意:我们必须通过接口

public interface myInterface
{
  void foo();
}

public class myClass implements myInterface
{
  private static myInterface instance;

  private myClass(){}

  private static myInterface Instance()
  {
     if(instance == null)
       instance = new myClass();

     return instance;
  }

  public void foo()
  {
    //Do stuff
  }

  public void bar()
  {
   //Do More Stuff
  }
}

这很好用,但是它不是线程安全的

private synchronized static myInterface Instance()
{
  if(instance == null)
    instance = new myClass();

  return instance;
} 

然后我转向一个枚举单例,它是线程安全的并且对系统来说并不繁重,但是我不确定如何将它编程到接口。

public enum myClass implements myInterface
{
  INSTANCE;
  private myClass(){}

  public void foo()
  {
    //Do stuff
  }

  public void bar()
  {
   //Do More Stuff
  }
}

在对接口进行编程时,我的意思是当我调用单例时,我只能访问接口中的方法(如果我指错了,请纠正我)。这就是我完成枚举单例的方式失败的地方。例如:对于惰性单例,我不能将其称为不在界面中:

 myClass.Instance().bar();

但是它可以调用这个是正确的,因为它是在界面中。

myClass.Instance().foo();

但是我可以使用枚举调用它,而不是对接口进行编程

myClass.INSTANCE.bar();

我理解为什么它作为类是一个枚举,所以它可以调用该枚举类中的所有内容。所以在我道歉的这篇长文之后,主要问题是:我可以让枚举版本只调用接口中声明的方法吗?

如果系统上的同步方法不能有多重,我会拥有大约 4-6 个?

请注意:尽管这是针对大学项目的,但我们只在一个线程上运行模拟,因此它甚至不需要是线程安全的。我不太了解多线程,但我认为这将是一个很好的学习机会。

【问题讨论】:

  • Re,“我读到 [同步] 对系统的影响很大。”那要看。您的程序会每秒调用 getter 数百万次吗?还是每小时几次?在您有证据表明确实存在 性能问题之前,不要浪费时间尝试解决性能问题(Google 表示“过早优化”)。此外,如果您的线程实际上 调用 getter 的频率足以导致问题,那么为什么不让每个线程缓存其自己的引用副本,而不是在每次需要引用时调用 getter?
  • 回复,“我有不少单身人士。”这听起来像是糟糕的设计。每当一个程序有“相当多”的 anything 时,您应该考虑如何将它们表示为 container 中的对象。
  • @jameslarge "我有很多单身人士" 这指的是我的“经理”和“工厂”,他们负责创建和维护实体、AI 行为等。知道这一点会您仍然认为这是一个糟糕的设计,为什么要允许多个经理?
  • 抱歉,我应该问一下“相当多”是什么意思。

标签: java multithreading enums singleton


【解决方案1】:

如果您更喜欢 enum 路由,您也可以随时隐藏您的 enum 实现:

public interface Singleton {
    void foo();
}

public final class SingletonAccessor {

    public static Singleton getInstance() {
        return SingletonImpl.INSTANCE;
    }

    private SingletonAccessor() {
    }

    private enum SingletonImpl implements Singleton {
        INSTANCE;
        public void foo() {
            // ...
        }
        public void bar() {
            // ...
        }
    }

}

编辑

正如 Peter Lawrey 在 cmets 中所指出的,您甚至可以为 SingletonAccessor 使用枚举 :)

public enum SingletonAccessor {

    SINGLETON;

    public Singleton get() {
        return SingletonImpl.INSTANCE;
    }

    private enum SingletonImpl implements Singleton {
        INSTANCE;
        public void foo() {
            // ...
        }
        public void bar() {
            // ...
        }
    }

}

【讨论】:

  • 您也可以将enum 用于 SingletonAccessor ;) +1
  • enum 不必有任何实例;)我称之为“实用程序”类。
  • @WillyduPreez 谢谢!这对我有用,我从没想过隐藏枚举实现使整个场景成为现实,但从没想过
【解决方案2】:

您可以将其投射到界面或

myInterface my = myClass.INSTANCE;
my.foo();

你仍然可以使用类似的方法

myClass.getInstance().foo();

但这不是一个真正的解决方案恕我直言。

我可以让枚举版本只调用接口中声明的方法吗?

最终,您必须决定要在实例上使用哪些方法,即public。如果您将方法或字段设为公开,则可以访问它,如果您不想访问,请将其设为私有。

在某些时候,您必须相信自己知道自己在做什么,并且做事是有原因的。您不必想办法阻止自己调用您编写的代码。

【讨论】:

    【解决方案3】:

    只需以这种方式更改您的单例类:

    public class myClass implements myInterface
    {
      private static myInterface instance = new myClass();
    
      private myClass(){}
    
      private static myInterface Instance()
      {
         return instance;
      }
    
      public void foo()
      {
        //Do stuff
      }
    
      public void bar()
      {
       //Do More Stuff
      }
    }
    

    这将确保在类加载时创建单例对象,您无需担心Instance() 方法中的竞争条件

    【讨论】:

    • 这比使用enum 更好吗?
    • 他的界面没有问题
    • 他可以使用enum,这样更简单,而且他不必担心忘记创建课程final
    • @PeterLawrey,他不能以他想要的方式使用它!这就是问题所在,对吧?
    • @PeterLawrey,然后再读一遍他的帖子,他认为,他的问题是,同步的Instance() 对系统来说很重,这是他尝试使用@987654327 的唯一原因@ 无论如何都是单身人士
    【解决方案4】:

    尝试查看 java.util.concurrent.atomic.AtomicReference。特别是 compareAndSet。

    instance.compareAndSet(null, new MyClass());
    

    即如果你的实例字段为空,则设置为新对象,如果不为空,则保持原样。应该不那么重。

    【讨论】:

    • 每次调用时都会创建一个对象。这可能比使用同步更昂贵。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-03-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-13
    • 2018-06-03
    • 2017-07-09
    相关资源
    最近更新 更多