2015-08-26 6 views
0

Я просто искал Google, чтобы узнать, как создать класс case с частным конструктором. Ниже правильный способ сделать это, как описано вcase class private constructor - need for readResolve реализация

How to override apply in a case class companion

object A { 
    def apply(s: String, i: Int): A = 
    new A(s.toUpperCase, i) {} //abstract class implementation intentionally empty 
} 
abstract case class A private[A] (s: String, i: Int) { 
    private def readResolve(): Object = //to ensure validation and possible singleton-ness, must override readResolve to use explicit companion object apply method 
    A.apply(s, i) 
    def copy(s: String = s, i: Int = i): A = 
    A.apply(s, i) 
} 

Ниже мое понимание до сих пор: -

Если мы объявляем случай класса аннотацию, то выполнение для копирования и применить метод не будет генерироваться компилятором.

Ниже вопрос, что я борюсь с: -

Почему требуется обеспечить выполнение readResolve?

+1

Я автор ответа на другую тему, на которую вы изначально задали этот вопрос. Я следую лучшей практике JVM/Java, основанной на совете Джошуа Блоха в его книге «Эффективная Java, второе издание». Исходная статья: http://stackoverflow.com/a/25538287/501113 – chaotic3quilibrium

+2

BTW, для более подробного контекста вокруг специфики JVM/Java метода readResolve и классов case, вот документ, который я написал (вместе с обновлением CodeReview), который углубляется вглубь в ПОЧЕМУ, я хотел, чтобы _allways предотвращали создание недействительных экземпляров класса case: https://docs.google.com/document/d/18SfBKHBUQ96dLYs-WyfzSKCFT6jrNF8FunMfCn55yMY/pub – chaotic3quilibrium

ответ

3

Реализация readResolve существует для предотвращения создания недопустимых экземпляров класса case путем редактирования сериализованных копий класса.

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

Это происходит из-за того, что классы case расширяют Serializable, и поэтому могут закончиться сериализацией и выпиской в ​​файл (или БД или где угодно). На этом этапе сериализованная копия в файле/DB/везде, где она может быть отредактирована, чтобы создать недопустимое значение (например, сделать s в нижнем регистре). При десериализации обратно экземпляр «live» будет недействительным, если только метод readResolve, который используется в процессе десериализации, не будет предотвращен.

+0

Могу ли я рассмотреть возможность реализации readResolve как наилучшей практики независимо от моего типа класса case (абстрактного или не абстрактного)? Что делать, если класс case не является абстрактным, тогда компилятор scala заботится о реализации readResolve? – mogli

+0

@rits Стандартный процесс десериализации Java создает экземпляр из считываемого потока (в основном просто считывая и настраивая отдельные поля экземпляра), а затем проверяет, определен ли метод readResolve. Если это так, он вызывается и его результат используется в качестве замены для создаваемого экземпляра. Этот механизм дает возможность дизайнеру класса модифицировать или полностью заменить экземпляр чтения как необходимо (здесь обеспечение 's' всегда занимает верхний регистр). Таким образом, по умолчанию обычно не требуется реализовать readResolve. – Shadowlands

+1

Scala отсылает стандартную библиотеку JVM/Java по умолчанию для Serialization. Таким образом, это будет больше о том, что лучше всего подходит для JVM/Java. Поскольку Сериализация используется МНОГО различными способами, включая, но не ограничиваясь, чтение/запись файлов, чтение/запись потока сокета в сети, чтение/запись процессов между JVM (хотя это не соответствует стилю, поскольку ОС теперь обеспечивают такой быстрый ввод-вывод с помощью сетевые сокеты, когда они расположены в одной и той же «машине»). и т. д. Итак, примените те же принципы к Scala, что и Java в этой области. – chaotic3quilibrium