2009-04-26 3 views
6

В моем проекте Java у меня есть вектор различных типов трейдеров. Эти различные типы трейдеров являются подклассами класса Trader. Прямо сейчас у меня есть метод, который принимает трейдера как аргумент и сохраняет его в векторе примерно 50 раз. У меня возникают проблемы, потому что хранение одного и того же объекта 50 раз - это просто сохранение 50 ссылок того же объекта. Мне нужно сохранить 50 экземпляров объекта. Я исследовал реализацию Clone, но я не хочу, чтобы программисты определяли тип трейдера, чтобы беспокоиться о том, чтобы сделать их класс клонированным. Кроме того, как указано в this page, реализация клона создает всевозможные проблемы. Я не думаю, что конструктор копирования работал бы потому, что, если бы я определил его в классе Trader, он не знал бы тип Trader, который он копировал, и просто создал общий трейдер. Что я могу сделать?Есть ли альтернативы реализации Clone в Java?

Редактировать: Я не очень хочу делать точные копии определенного объекта. То, что я действительно пытаюсь сделать, это добавить определенное количество трейдеров к вектору. Проблема в том, что пользователь должен указать в аргументе, какой тип трейдера он хочет добавить. Вот пример того, что я пытаюсь сделать: (хотя мой синтаксис полностью мнимая)

public void addTraders(*traderType*) 
{ 
    tradervect.add(new *traderType*()) 
} 

Как я могу добиться чего-то вроде этого в Java?

ответ

2

Просто добавьте абстрактный метод копирования. Вы можете использовать ковариантные типы возвращаемых данных, чтобы указать производный тип для возврата производного экземпляра, который может быть или не быть важен.

public interface Trader { 
    Trader copyTrader(); 
    ... 
} 


public final class MyTrader implements Trader { 
    MyTrader copyTrader() { 
     return new MyTrader(this); 
    } 
    ... 
} 

Иногда вы можете обобщенно дело с коллекцией производного типа Trader, который необходимо клонировать, а затем вернуть правильно набранный коллекцию. Для этого вы можете использовать дженерик в идиоматическом образе:

public interface Trader<THIS extends Trader> { 
    THIS copyTrader(); 
    ... 
} 


public final class MyTrader implements Trader<MyTrader> { 
    public MyTrader copyTrader() { 
     return new MyTrader(this); 
    } 
    ... 
} 
+0

Я не вижу, как я могу сделать общий класс Trader интерфейсом, потому что класс Trader имеет методы, которые должны быть доступны. Создание интерфейса означало бы, что все эти методы низкого уровня не позволят определять эти методы в классе Trader. –

+0

Независимо от того, является ли Trader абстрактным классом или интерфейсом, это не имеет значения. Как правило, интерфейс предпочтительнее абстрактного класса. Также предпочитаем делегировать наследование. –

0

Один из вариантов. Если вы можете сделать объекты сериализуемыми, вы можете сериализовать, а затем десериализовать его, чтобы сделать копию, аналогичную тому, что происходит при передаче объекта через RMI.

Быстрый метод копирования:

public MyObject copy() { 
    ObjectOutputStream oos = null; 
    ObjectInputStream ois = null; 
    try { 
     ByteArrayOutputStream bos = new ByteArrayOutputStream(); 
     oos = new ObjectOutputStream(bos); 
     oos.writeObject(this); 
     oos.flush(); 
     ByteArrayInputStream bin = 
      new ByteArrayInputStream(bos.toByteArray()); 
     ois = new ObjectInputStream(bin); 
     return (MyObject)ois.readObject(); 
    } catch(Exception e) { 
     return null; 
    } finally { 
     try { 
      oos.close(); 
      ois.close(); 
     } catch (Exception e) { 
      return null; 
     } 
    } 
} 
+0

Почему downvote? Это адекватный способ описания сложного объекта. Однако управление ресурсами полностью и полностью нарушено. –

+0

Это единственное решение? Я не могу заставить себя поверить, что такая простая операция вызовет столько шума. Что делать, если я буду использовать Clone для копирования. Это возможно? –

+0

@Tom: Не уверен, но использование сериализации/десериализации для клонирования примерно так же тонко, как использование memcpy вместо конструкторов копирования в C++. – Uri

-2

Один из способов сделать это конечный классом, как собственная строка в Java, который будет делать какие-либо изменения в объект класса Trader, чтобы создать новую копию в памяти , но это сделает невозможным подкласс.

Другим (лучшим) способом является использование фабричного метода для создания и копирования объектов Trader objexts, что подразумевает, что вы не должны допускать использование конструктора по умолчанию, т. Е. Сделать его закрытым. Таким образом, вы можете контролировать количество экземпляров класса. См http://en.wikipedia.org/wiki/Factory_method

public class Trader { 

    /* prevent constructor so new cant be used outside the factory method */ 
    private Trader() { 
    } 

    /* the factory method */ 
    public static Trader createTrader(int whatKindOfTrader) { 

     switch (whatKindOfTrader) { 
     case 0: 
      return new Trader1(); // extends Trader 
     case 1: 
     default: 
      return new Trader2(); // extends Trader 
     } 
     return new Trader3(); // or throw exception 
    } 
} 

Можно даже указать другой перегруженный метод, или второй аргумент, который принимает один трейдер и копирует его в новый, заменяя таким образом клон. Кстати, вы можете переопределить метод clone() и выбросить CloneNotSupportedException, чтобы предотвратить клонирование Object объекта по умолчанию.

+0

Вы имеете в виду неизменный, а не только последний класс. Неизменность, вероятно, будет немного далека от объекта «трейдер». –

+0

Я не был неизменным, но окончательным. Есть разница, и лично я никогда не буду ее использовать. Но, метод Factory - это лучшая практика, и это общий шаблон дизайна. Btw, неизменный объект просто не пригоден в этом случае. – Azder

2

Я немного неясен, почему вы хотите хранить 50 или около того клонов одного и того же объекта, если они не являются оригинальным трейдером в качестве прототипа (см. Рисунок) для более поздних трейдеров.

Если вы хотите сделать точную копию объекта, вы должны учитывать проблему полиморфизма. Если людям, подклассифицирующим ваш класс, разрешено добавлять государства-члены, то у вас уже достаточно головной боли с такими функциями, как equals и compareTo, этот клон - это еще один случай, когда вам нужно будет потребовать специальной обработки.

Я не согласен, что клон всегда злой, иногда это необходимо. Однако в ситуациях подкласса многие вещи становятся сложными.

Я бы порекомендовал вам прочитать (когда у вас появится шанс) «Эффективная Java» Блоха, которая охватывает множество его тем. Брача считает, что не рекомендуется позволять другим расширять ваши классы, и если вы это сделаете, вам нужно хорошо документировать, что им нужно делать, и надеяться, что они последуют вашим инструкциям. На самом деле нет способа обойти это. Вы также можете сделать своих трейдеров неизменными.

Выполняйте клонирование объектов в обычном режиме и четко указывайте в заголовке класса, что любой, унаследовавший от вашего трейдера и добавляющий элементы состояния, должен реализовать методы X (указать, какие).

Поиск трюков в обход реального Cloneable и Still Clone не собирается преодолевать проблему наследования. Здесь нет серебряной пули.

+0

Ваш ответ заставил меня задуматься. См. Редактирование, которое я сделал для получения дополнительной информации.:) –

+0

Подождите, вы говорите, что если X расширяет Trader, а кто-то передал экземпляр X вашей функции, вы хотите получить еще один новый X? – Uri

+0

Если вы хотите этого, вы используете (ужасный) getClass.newInstance идиомы:. traderType.getClass() newInstance() Вы должны убедиться, что всегда есть открытый конструктор, и вы, вероятно, хотите, чтобы некоторые инициализации метод, который вы всегда можете вызвать, чтобы привести его в законное состояние. – Uri

0

Uri's right, полиморфизм с государством открывает большую банку червей.

Я думаю, что подклассы Cloneable и overrideing clone(), вероятно, самый простой способ. Вы можете, я полагаю, сделать возвращаемый тип ковариантным.

 Смежные вопросы

  • Нет связанных вопросов^_^