我有多个类不允许修改彼此的字段,而是必须通过向Main类的队列添加请求对象来请求修改。 Main类在每个循环结束时将执行所请求的修改。
public class Main {
public static ClassA a = new ClassA();
public static ClassB b = new ClassB();
private static List<Request> requestQueue = new ArrayList<Request>(); // List holds all requests
public static void main(String args[]) {
while (true) {
a.tick();
b.tick();
for (Request r : requestQueue) {
r.field = r.value; // All requests are fulfilled
}
requestQueue.clear();
}
}
public static <ValueType> void addModificationRequest(ValueType field,
ValueType value) {
requestQueue.add(new Request<ValueType>(field, value));
}
}
// Request Object
public class Request<ValueType> {
ValueType field;
ValueType value;
public Request(ValueType field, ValueType value) {
this.field = field;
this.value = value;
}
}
// Classes
public class ClassA {
String name = "A";
public void tick() {
Main.addModificationRequest(Main.b.name, "NewNameB"); // Try to change b name
}
}
public class ClassB {
String name = "B";
public void tick() {
// Nothing
}
}
我知道代码很乱,但它是迄今为止我想到的最简单的方法。有谁知道任何可以以更简单和更健壮的方式实现这一目标的良好设计模式? (注意:我必须这样,不允许类直接相互修改。)
编辑:这些类将包含多个可修改的变量。我还需要确定是否有任何请求尝试修改同一个变量,因此我可以忽略其中一个或两个。
编辑:感谢所有的帮助,我真的很感激!我决定让课程跟踪他们自己的修改。我也将使用我一直使用的相同Request对象,因为它简单明了。再次,谢谢。
答案 0 :(得分:1)
也许这不适用于您的用例,但您可以让对象自己跟踪待处理的修改,然后从您的主类调用,修改自己的实际字段。
如果您只需要设置操作,跟踪修改就像为类中的每个字段保留额外字段一样简单。如果您需要一系列算术运算,则可以使用修改列表。
public class DelayedModificationField<T> {
private T field;
private T newValue;
public T get() { return field;}
public delayedSet(T value) {
if (newValue != null) throw new ConcurrentModificationException("error");
newValue = value;
}
public void performSet() {
field = newValue;
newValue = null;
}
public ExampleClass {
private DelayedModificationField<String> myField = new DelayedModificationField<String>();
public void setMyField(String s) { myField.delayedSet(s);}
public String getMyField() { return myField.get();}
public void performSet() { myField.performSet();}
}
您的主类必须跟踪支持延迟修改的所有对象,并在每个tick上调用performSet。让它们实现一个接口并将它们保存在列表中。
答案 1 :(得分:0)
这不起作用。我不知道您的作业的确切参数,但我会使用单个方法Modifiable
定义接口void setField(ValueType newValue)
。然后我会声明ClassA
和ClassB
来实施Modifiable
。最后,将您的Request
课程重新定义为Modifiable
和ValueType
,而不是两个ValueType
字段。您的队列循环将是:
for (Request r : requestQueue) {
r.modifiable.setField(r.value);
}
编辑:
以下是对此方法的修改,可以扩展到多个字段:
interface Modifiable {
void setName(String newName);
void setAge(Integer newAge); // I wish
}
abstract class Request<ValueType> {
Modifiable object;
ValueType value;
public Request(Modifiable object, ValueType value) {
this.object = object;
this.value = value;
}
abstract void execute();
}
class RequestNameChange extends Request<String> {
public RequestNameChange(Modifiable object, String name) {
super(object, name);
}
void execute() {
object.setName(name);
}
}
// etc.
另一种方法是使用反射,但我怀疑这不是你的任务所在。
答案 2 :(得分:0)
尝试“好莱坞”模式 - 它采用“不要打电话给我们,我们会打电话给你”的风格,即使用“回调”代码。
像这样:
public static class Main {
public static ClassA a = new ClassA();
public static ClassB b = new ClassB();
private static List<Runnable> requestQueue = new ArrayList<Runnable>(); // List holds all requests
public static void main(String args[]) {
while (true) {
a.tick();
b.tick();
for (Runnable r : requestQueue) {
r.run(); // All requests are fulfilled
}
requestQueue.clear();
}
}
public static void addModificationRequest(Runnable runnable) {
requestQueue.add(runnable);
}
}
使用匿名类调用addModificationRequest:
Main.addModificationRequest(new Runnable() {
public void run() {
Main.b.name = "NewNameB";
}
});
请注意,如果在foreach循环执行时调用addModificationRequest,则此代码将抛出ConcurrentModificationException
。一个便宜的修复方法是将关键字synchronized
添加到addModificationRequest,并使用类对象作为锁执行同步块中的循环+清除。
编辑:
要传入该字段,您也可以查看它,试试这个:
interface FieldUpdater extends Runnable
{
Field getField();
}
static class Main
{
public static ClassA a = new ClassA();
public static ClassB b = new ClassB();
private static List<FieldUpdater> requestQueue = new ArrayList<FieldUpdater>(); // List holds all requests
private static Set<Field> seenBefore = new HashSet<Field>();
public void main(String args[])
{
while (true)
{
a.tick();
b.tick();
for (FieldUpdater r : requestQueue)
{
if (seenBefore.contains(r.getField()))
{
continue; // Or do something else specific
}
seenBefore.add(r.getField());
r.run();
}
requestQueue.clear();
}
}
public synchronized static void addModificationRequest(FieldUpdater fieldUpdater)
{
requestQueue.add(fieldUpdater);
}
}
然后按照以下方式调用您的方法:
Main.addModificationRequest(new FieldUpdater()
{
public void run()
{
Main.b.name = "NewNameB";
}
public Field getField()
{
return Main.class.getField("name");
}
});
请注意,为清楚起见,我故意省略了处理可以从getField()抛出的异常。此外,这不是很好的代码设计,但它确实解决了所述的代码修复问题。