0

タスク間で 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 タスククラスで共有。このように、クライアントコード(Task Queue)はタスクテーブルのconfigに書き込む(Taskの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

おそらく、2 番目の方法は使用したくないでしょう。2 つの s を格納するような単純なものintでは、リフレクションは少し過剰に思えます。これによって得られるメモリ パフォーマンスの量は非常に小さいため、jvm はメソッドのオーバーロードを把握するために、より多くの作業を行う必要があります。より多くのコードスペースを占有することになり (Java コンパイラーはこの余分な情報をどこに保管していると思いますか?)、実行速度が低下します。

最初の方法はそれを行う 1 つの方法ですが、2 つintの s を保存するのと同じくらい簡単な場合Taskは、別のキーを使用する代わりに、クラスに 2 つのキーのみを使用することを検討してください。

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[][]取得する必要がある場合を除き、このすべてのデータを既に保存していることを考えると、これを行う必要はないようです。代わりに直接行うことができますkey1key2Task

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

ただし、特定のオブジェクトの値を取得する必要がある場合は、代わりに a を使用しkey1てデータを保存できます。そうすればできる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 に答える