【发布时间】:2010-08-03 17:49:13
【问题描述】:
我想编写一个只能实例化 5 次的 java 类,就像你的单例类只有一个实例一样。
除此之外,实例应该循环选择。
假设我有一个 A 类。我应该只能创建该类的 5 个实例。 假设我有 InstanceA_1、InstanceA_2、InstanceA_3、InstanceA_4、InstanceA_5。每当我需要使用它们时,都应该在循环的基础上挑选它们。
【问题讨论】:
标签: java design-patterns
我想编写一个只能实例化 5 次的 java 类,就像你的单例类只有一个实例一样。
除此之外,实例应该循环选择。
假设我有一个 A 类。我应该只能创建该类的 5 个实例。 假设我有 InstanceA_1、InstanceA_2、InstanceA_3、InstanceA_4、InstanceA_5。每当我需要使用它们时,都应该在循环的基础上挑选它们。
【问题讨论】:
标签: java design-patterns
正如Effective Java 2nd Edition推荐enum来实现单例,这个解决方案也使用enum来实现...四元组?
import java.util.*;
public enum RoundRobin {
EENIE, MEENIE, MINY, MO;
private final static List<RoundRobin> values =
Collections.unmodifiableList(Arrays.asList(values()));
// cache it instead of creating new array every time with values()
private final static int N = values.size();
private static int counter = -1;
public static RoundRobin nextInstance() {
counter = (counter + 1) % N; // % is the remainder operator
return values.get(counter);
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
System.out.println(RoundRobin.nextInstance());
}
// EENIE, MEENIE, MINY, MO, EENIE, MEENIE, MINY, MO, ...
}
}
将此扩展到五元组是不言自明的。
从 1.5 版开始,还有第三种实现单例的方法。只需使用一个元素创建一个枚举类型。这种方法在功能上等同于公共字段方法,只是它更简洁,免费提供序列化机制,并且即使面对复杂的序列化或反射攻击,也可以防止多次实例化。虽然这种方法尚未被广泛采用,但单元素枚举类型是实现单例的最佳方式。
【讨论】:
== 而不是 equals 如果您选择这样做。
nextInstance 可以变成synchronized 和counter 是volatile,或者也许可以使用原子模块counter,等等。好点。
您需要Object pool 之类的东西。最简单的实现是有一个包含 5 个对象的 List 的单例,并且每当您调用 getInstance(..) 时,应该迭代列表并返回其中一个对象。
【讨论】:
这是作业吗?
你为什么不创建一个工厂来创建 5 个实例并将它们存储在一个列表中?当有人调用 Factory.getInstance() 时,它将使用列表的正确索引获取正确的实例。
【讨论】:
游泳池可以工作吗(例如Apache Commons Pool)?
【讨论】:
嗯,大致是这样的:
为了线程安全,您需要在静态方法中锁定。您可以使用 AtomicInteger,但包装很棘手。您始终可以使用 AtomicInteger 或 AtomicLong,每次递增,并使用 % 运算符进行索引...但是当索引换行时,您会遇到不连续性。这对你来说可能是也可能不是问题。
(这是假设您不介意预先创建所有五个实例。这肯定会让事情变得更容易。)
【讨论】:
我想您需要做的就是扩展单例模式以使用计数器。比如……
// Declare a list holding the 5 Objects
List<Foo> instances = new ArrayList<Foo>(5);
// Keep track of which Object you are returning next
int curr = 0;
...
static Foo getInstance() {
// Only instantiate when necessary
if (instances.get(curr) == null) {
instances.set(curr, new Foo());
}
Foo toReturn = instances.get(curr);
// Use modulus to loop back to 0 after 4
curr = (curr + 1) % 5;
return toReturn;
}
免责声明:我假设您不需要代码是线程安全的。
【讨论】:
Integer.MAX_VALUE 时会发生什么?模数方法还能正确计算吗?
curr 永远不会大于 4。:)
这是一个非常简单的解决方案。请注意,这不是线程安全的:
class ClassA {
private final List<ClassA> instances = Arrays.asList(new ClassA(), new ClassA(), new ClassA(), new ClassA(), new ClassA());
private ClassA() {}
public static ClassA getInstance() {
Collections.shuffle(instances);
return instances.get(0);
}
}
【讨论】:
创建五个静态实例。保留最后一个实例的索引。创建一个私有构造函数。使用方法获取实例(类似于单例);
public class MyObject {
private static final MyObject instance_1 = new MyObject();
private static final MyObject instance_2 = new MyObject();
private static final MyObject instance_3 = new MyObject();
private static final MyObject instance_4 = new MyObject();
private static final MyObject instance_5 = new MyObject();
private static final MyObject[] instances = new MyObject[]{instance_1, instance_2,instance_3, instance_4,instance_5};
private MyObject() {
}
private static volatile int index = 0; //in a multi-threaded evironment, you should use volatile
/**
* The following code is not thread safe
*/
public static MyObject getInstance() {
MyObject instance = instances[index];
if (index == 4) {
index = 0;
} else {
index++;
}
return instance;
}
}
【讨论】:
new MyObject[] { new MyObject(), ... }.
class OnlyFiveTime {
private static LinkedList<OnlyFiveTime> instaces = new LinkedList<OnlyFiveTime>();
private static final int count = 5;
public static OnlyFiveTime getInstace() {
if(instaces.size() != count) {
instaces.addLast(new OnlyFiveTime());
}
OnlyFiveTime robinRound = instaces.removeFirst();
instaces.addLast(robinRound);
return robinRound;
}
private OnlyFiveTime() {
}
}
【讨论】:
一个简化的循环。
import java.util.*;
public enum RoundRobin {
EENIE, MEENIE, MINY, MO;
private final static RoundRobin[] values = values();
private static int counter = -1;
public static RoundRobin nextInstance() {
counter = (counter + 1) % values.length;
return values[counter];
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++)
System.out.println(RoundRobin.nextInstance());
// EENIE, MEENIE, MINY, MO, EENIE, MEENIE, MINY, MO, ...
}
}
【讨论】:
您必须创建静态实例变量来跟踪所有对象。然后您可以在构造函数上使用 if 语句来引发异常或在用户初始化类 5 次时退出系统。
public class JustFive {
public static int count;
public JustFive(){
if(count>=5){
System.out.println("you can not create another instance");
System.exit(1);
}
else count++;
System.out.println(count);
}}
您可能想使用静态工厂方法。我正在向您展示不推荐的不寻常方式。
【讨论】: