0

Tasks之间共享TaskKey,哪个更好?还有其他更好的方法吗?

way1 通过一个关键对象共享。这样,客户端代码(任务队列)更容易编写配置任务表。但是每个任务都必须浪费内存来存储 TaskKey 对象。

class TaskKey {
    int key1;
    int key2;
    // key3...
    TaskKey(int key1, int key2) {
        this.key1 = key1;
        this.key2 = key2;
    }
}

abstract class Task implements Cloneable {
    TaskKey key;
    int taskData;
    Task(TaskKey key) {
        this.key = key;
    }
    int getKey1() {
        return key.key1;
    }
    int getKey2() {
        return key.key2;
    }
    Task newInstance(int taskData) {
        Task task = (Task) clone();
        task.taskData = taskData;
        return task;
    }
    abstract void doSomething();
}

class TaskQueue {
    Task[][] taskTable;
    void addTask(Task task) {
        taskTable[task.getKey1()][task.getKey2()] = task;
    }
    void config() {
        addTask(new Task(new TaskKey(1, 1)) {
            void doSomething() {}
        });
        addTask(new Task(new TaskKey(1, 2)) {
            void doSomething() {}
        });
        addTask(new Task(new TaskKey(2, 1)) {
            void doSomething() {}
        });
    }

    Queue<Task> queue;
    void put(int key1, int key2, int taskData) {
        Task task = taskTable[key1][key2];
        queue.add(task.newInstance(taskData));
    }
}

way2 由任务类共享。这样,客户端代码(任务队列)写配置任务表很麻烦(重写任务的getKey()方法)。但是每个任务都不需要浪费内存来存储TaskKey对象,因为关键信息是由具体的Task类共享的。

abstract class Task implements Cloneable {
    int taskData;
    abstract int getKey1();
    abstract int getKey2();
    abstract void doSomething();
    Task newInstance(int taskData) {
        Task task = (Task) clone();
        task.taskData = taskData;
        return task;
    }
}

class TaskQueue {
    Task[][] taskTable;
    void addTask(Task task) {
        taskTable[task.getKey1()][task.getKey2()] = task;
    }
    void config() {
        addTask(new Task() {
            int getKey1() { return 1; }
            int getKey2() { return 1; }
            void doSomething() {}
        });
        addTask(new Task() {
            int getKey1() { return 1; }
            int getKey2() { return 2; }
            void doSomething() {}
        });
        addTask(new Task() {
            int getKey1() { return 2; }
            int getKey2() { return 1; }
            void doSomething() {}
        });
    }

    Queue<Task> queue;
    void put(int key1, int key2, int taskData) {
        Task task = taskTable[key1][key2];
        queue.add(task.newInstance(taskData));
    }
}

另一种方式1和方式2

interface TaskExecutor {
    void exec(Task task);
}

class TaskKey {
    int key1;
    int key2;
    int key3;
    TaskExecutor executor;
}

class Task /*another way1*/ {
    TaskKey key;
    int taskData;// in fact it is not only a int

    int getKey1() { // because i need to retrieve key1 from a task
        return key.key1;
    }
    // also get methods for key2 key3

    void exec(){
        key.executor.exec(this);
    }
}

class Task /*another way2*/ {
    public final int key1;
    public final int key2;
    public final int key3;
    private final TaskExecutor executor;
    int taskData;

    void exec(){
        executor.exec(this);
    }
}
4

1 回答 1

0

你可能不想用第二种方式。对于像存储两个ints 这样简单的事情,反射似乎有点矫枉过正。您从中获得的内存性能非常小,jvm 将不得不更加努力地找出您的方法重载。它最终会占用更多的代码空间(您认为 java 编译器在哪里存储所有这些额外信息?)以及减慢执行速度。

第一种方法是一种方法,但如果它像存储两个ints 一样简单,您可能会考虑在Task类中只使用两个键而不是单独的键。

abstract class Task implements Cloneable {
    int taskData;
    int key1;
    int key2;
    Task(int key1_, int key2_) {
        this.key1 = key1_;
        this.key2 = key2_;
    }
    int getKey1() {
        return key1;
    }
    int getKey2() {
        return key2;
    }
    Task newInstance(int taskData) {
        Task task = (Task) clone();
    task.taskData = taskData;
        return task;
    }
    abstract void doSomething();
}

但是,考虑到您已经存储了所有这些数据,您似乎不需要这样做Task[][],除非您需要从特定对象获取值key1,否则您可以直接执行key2Task

void addTask(Task task, int i, int j) {
    taskTable[i][j] = task;
}
void config() {
    addTask(new Task(), 1, 1);
}

但是,如果您确实需要从特定对象中获取值key1,则可以使用 a而不是 a来存储数据。这样你就可以key2TaskHashMap<TaskKey,Task>Task[][]

HashMap<TaskKey,Task> taskTable;
void addTask(Task task, int i, int j) {
    taskTable.put(new TaskKey(i,j), task);
}
Task getTask(int i, int j){
    return taskTable.get(new TaskKey(i,j));
}
void config() {
    addTask(new Task(), 1, 1);
}

尽管您可能需要使用您最喜欢的 IDE 为它们生成一个hashCode()and方法。equals()这最终会非常节省内存,并且具有与数组相同的恒定时间访问。

于 2012-06-08T13:46:14.247 回答