2012-02-10 2 views
15

Была попытка найти лучший способ реализовать метод, который создает защитную копию объекта Calendar.Оборонительная копия календаря

например:

public void setDate(Calendar date) { 
    // What to do.... 
} 

Я особенно обеспокоен чередованием потоков при проверке нулевой вход и сделать копию или я упускаю что-то очень очевидное?

+1

В чем проблема с клоном? (Мне действительно интересно) – zeller

+0

Хорошая точка, клон клон хорош, если сам объект не расширяется, к сожалению, Calendar (GregorianCalendar) есть, но клон можно использовать, если я уверен, что объект является Календарем и никаким другим непослушным подклассом. На самом деле, я использую метод clone в getter того же класса, потому что я уверен, что мой внутренний календарь на самом деле таков. –

+0

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

ответ

22

(Направленная на несколько иной аудитории сейчас, я думаю ...)

Я хотел бы использовать clone(), если я абсолютно пришлось использовать Calendar вообще (вместо Joda времени). Вы утверждаете в комментариях, что вы беспокоитесь о «непослушном подклассе» - как бы вы предложили обойти это в любой схеме? Если вы ничего не знаете о вовлеченных подклассах и не доверяете им, то у вас нет способа сохранить данные типа. Если вы не доверяете подклассу, чтобы не повредить вещи, у вас больше проблем в целом. Как вы доверяете ему, чтобы дать правильные результаты при выполнении расчетов даты и времени?

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

Преимущества по сравнению с использованием Calendar.getInstance() и Настройка свойств себя:

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

EDIT: В терминах «чередование потоков», который первоначально вопрос забота о: значениях параметра date не изменит любые другие потоки делать. Однако, если другой поток мутирует содержимое объекта, когда вы берете защитную копию, то может очень легко вызвать проблемы. Если это риск, то у вас есть большие проблемы, в основном.

15

Простейшее путь будет:

copy = Calendar.getInstance(original.getTimeZone()); 
copy.setTime(original.getTime()); 

Но я настоятельно рекомендую (по возможности) использовать JodaTime выразить времени и даты в Java. Он имеет неизменные классы, а также изменчивые.

+2

Я думаю, что это не гарантирует, что календари будут в одном и том же – zeller

+0

Да, мне нравится, когда это происходит, я беспокоился о чередовании между параллельными потоками при проверке нулевого значения, а затем, следовательно, установке копии на метку времени оригинала, я думаю, что это проблема, которую я собираюсь чтобы жить. Да, я слышал очень хорошие вещи о JodaTime, я должен признать, что у меня нет опыта с ним, хотя :) Посмотрите. –

+2

@zeller Вы правы в отношении часовых поясов. Я отредактировал этот пример. –

1

Просто обведите свой объект Calendar в ThreadLocal. Это гарантирует, что каждый экземпляр Календаря используется только одним потоком. Что-то вроде этого:

public class ThreadLocalCalendar 
{ 
    private final static ThreadLocal <Calendar> CALENDAR = 
     new ThreadLocal <Calendar>() 
     { 
      @Override 
      protected Calendar initialValue() 
      { 
       GregorianCalendar calendar = new GregorianCalendar(); 

       // Configure calendar here. Set time zone etc. 

       return calendar; 
      } 
     }; 

    // Called from multiple threads in parallel 
    public void foo() 
    { 
     Calendar calendar = CALENDAR.get(); 

     calendar.setTime (new Date()); 
     // Use calendar here safely, because it belongs to current thread 
    } 
} 
0

Этого невозможно гарантировать!

Безопасность нитей: не может быть обеспечена, если вы не знаете о схеме безопасности, осуществляемой стороной, откуда вы получили ссылку. Эта сторона могла бы дать вам новую ссылку, и в этом случае вы можете просто использовать ссылку как есть. Эта сторона могла опубликовать свою схему безопасности в отношении этой ссылки в Календаре, и в этом случае вы можете следовать одной и той же схеме (иногда это будет невозможно) для проверки непустых ссылок, типа, а затем копировать с помощью getInstance() , Не зная об этом, невозможно обеспечить безопасность потоков, я думаю.

Оборонительное копирование календаря: клонирование - это не вариант, если вы не доверяете месту, откуда вы получили ссылку! Календарь не поддерживает конструктор, который принимает существующий объект Calender и создает новый!

Короче говоря, не существует способа решить вашу проблему. JodaTime - лучший способ продвижения вперед.

-2

Я предлагаю использовать «синхронизированный блок» здесь.

+0

Синхронизация ничего не сделает с принятием защитной копии. –

2

Я знаю, что это уже давно, но я думал, что поставлю свои два цента.

Если вы программируете по контракту, объект не несет ответственности за ошибки другого объекта. Календарь реализует Cloneable, что означает, что подклассы тоже! Если подкласс Календаря разбивает контракт на Cloneable, необходимо подправить подкласс, а не клон вызова класса.

В программировании ОО объект должен заботиться только о классах &, с которыми он связан. Это усложняет дизайн значительно, по факторам, когда вы спрашиваете: «Что, если подкласс сломает его?» Всякий раз, когда объект принимает объект как параметр, всегда есть вероятность, что объект является подклассом и разбивает все. Вы программируете оборонительно, когда вы вызываете getX(), что он не генерирует исключение ArithmeticException для подклассов?

Jon Skeet предоставил отличный ответ, лучше, чем мой, но я подумал, что потенциальный споткнуться на этот вопрос может выиграть от прослушивания незначительной части «Дизайн по контракту». Хотя подход близок к смерти, методология помогла моим проектам спокойно много.

0

Как насчет нижеследующего?

public synchronized void setDate(Calendar date) { 
    // What to do.... 
    Calendar anotherCalendar = Calendar.getInstance(); 
    anotherCalendar.setTimeInMillis(date.getTimeInMillis()); 
} 

Правильное использование в синхронизированном коде зависит от вашего прецедента.

+0

Может также работать, я предпочитаю клон-ответ, хотя, в идеальном мире с неизменным типом - клон будет способом, я думаю, но ваш ответ также является правильной попыткой –

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