Строго типизированный идентификатор — это определяемый пользователем тип данных , который служит идентификатором или ключом, который строго типизирован . Это решение для « запаха кода примитивной одержимости» , упомянутого Мартином Фаулером . Предпочтительно, чтобы тип данных был неизменяемым , если это возможно. Обычно реализации обрабатывают проверку равенства, сериализацию и связывание моделей.
Строго типизированный идентификатор обычно охватывает тип данных, используемый в качестве первичного ключа в базе данных, например строку, целое число или универсальный уникальный идентификатор (UUID).
Веб-фреймворки часто можно настроить для моделирования свойств привязки к моделям представлений, которые являются строго типизированными идентификаторами. Объектно-реляционные преобразователи часто можно настроить с преобразователями значений для сопоставления данных между свойствами в модели с использованием строго типизированных типов данных идентификаторов и столбцов базы данных.
Передача строго типизированного идентификатора через слои примера приложения.
В C# есть записи, которые обеспечивают неизменность и проверку на равенство. [1] Запись запечатана, чтобы предотвратить наследование . [2] Она переопределяет встроенный ToString()
метод. [3]
В этом примере реализации используется статический метод, который можно использовать для инициализации нового экземпляра с помощью случайно сгенерированного глобального уникального идентификатора (GUID).
/// <summary> /// Представляет идентификатор пользователя. /// </summary> /// <param name="Id">Идентификатор пользователя.</param> public sealed record UserId ( Guid Id ) { /// <summary> /// Инициализирует новый экземпляр записи <see cref="UserId" />. /// </summary> /// <returns>Новый объект UserId.</returns> public static UserId New () => new ( Guid . NewGuid ()); публичная переопределенная строка ToString ( ) => Id.ToString ( ); }
В C++ есть структуры, но нет неизменяемости, поэтому здесь поле id помечено как закрытое с указанным методом value()
получения значения.
структура UserId { UserId ( конст строка _id ) { id = _id ; } строковое значение () const { return id ; } оператор bool == ( const UserId & rhs ) const { возвращаемое значение () == rhs . значение (); } частный : строковый идентификатор ; }; ostream & оператор << ( ostream & os , const UserId & id ) { return os << id . value () << std :: endl ; }
Стандартная библиотека Crystal предоставляет макрос записи для создания записей, которые являются неизменяемыми структурами, и позволяет вам переопределять встроенный to_s
метод. [4]
требуется "uuid" # Представляет идентификатор пользователя. record UserId , id : String do def initialize () @id = UUID . v4 . to_s end def to_s ( io ) io << id конец def self.empty self.new ( UUID .empty .to_s ) конец конец
D имеет неизменяемые структуры. [5]
импорт стандартный ; /** Представляет идентификатор пользователя. */ immutable struct UserId { immutable UUID id ; /** Инициализирует новый экземпляр структуры UserId. */ this ( immutable string id ) { this . id = UUID ( id ); } public static UserId create ( ) { return UserId ( randomUUID.toString ( ) ); } строка toString ( ) { вернуть это.id.toString ( ) ; } }
В Dart есть классы с перегрузкой операторов.
импорт 'package:meta/meta.dart' ; /// Представляет идентификатор пользователя. @immutable final class UserId { final String id ; /// Инициализирует новый экземпляр структуры UserId. const UserId ( this . id ); @override оператор == ( other ) => other is UserId && other . id == id ; @override int get hashCode => id . hashCode ; @override String toString () => id ; }
F# позволяет создавать переопределенные методы Equals
, GetHashCode
и ToString
.
открытая система /// <summary> /// Представляет идентификатор пользователя. /// </summary> /// <param name="id">Идентификатор пользователя.</param> type UserId ( id : Guid ) = member x . id = id static member New () = Guid . NewGuid () static member Empty = Guid . Empty override x . Equals ( b ) = match b with | :? UserId as p -> id = p . id | _ - > false override x . GetHashCode () = hash id override x . ToString () = id . ToString ()
В Go есть структуры, которые обеспечивают проверку равенства. Однако Go не обеспечивает неизменяемости.
// Представляет идентификатор пользователя. type UserId struct { id string } // Создает новый идентификатор пользователя. func NewUserId ( id string ) UserId { return UserId { id : id } } func ( xUserId ) String ( ) string { return x.id }
В Groovy есть классы записей, которые обеспечивают неизменность и проверку равенства. [6]
/** * Представляет идентификатор пользователя. * * @param id Идентификатор пользователя. */ record UserId ( String id ) { String toString () { id } }
Haskell может создавать пользовательские типы данных, используя newtype
ключевое слово. [7] Он обеспечивает проверку равенства с использованием Eq
стандартного класса и печать с использованием стандартных классов Read
и Show
.
-- Представляет идентификатор пользователя. newtype UserId = UserId String deriving ( Eq , Read , Show )
В Java есть записи, которые обеспечивают проверку равенства. [8]
Запись объявляется с использованием final
ключевого слова modifier для предотвращения наследования. Она переопределяет встроенный toString()
метод.
импорт java.util.UUID ; /** * Представляет идентификатор пользователя. * @param id Идентификатор пользователя. */ public final record UserId ( UUID id ) { /** * Инициализирует новый экземпляр записи UserId. * @return Новый объект UserId. */ public static UserId newId () { return new UserId ( UUID . randomUUID ()); } public String toString () { return id . toString (); } }
Этот пример реализации JavaScripttoJSON
предоставляет метод, используемый функцией JSON.stringify()
[9] для сериализации класса в простую строку вместо составного типа данных . Он вызывает, Object.freeze()
чтобы сделать экземпляр неизменяемым. [10]
Он переопределяет встроенный toString()
метод [11] и valueOf()
метод. [12]
класс UserId { # id ; конструктор ( id ) { if ( id == undefined ) { throw new TypeError ( "Аргумент равен null или не определен." ); } this . # id = id ; Object . freeze ( this ); } статический пустой = новый этот.прототип.конструктор ( " 00000000-0000-0000-0000-000000000000 " ) ; static new ( ) { return new this.prototype.constructor ( crypto.randomUUID ( ) ) ; } equals ( id ) { return id instanceof this.constructor && this . # id === id.valueOf ( ) ; } toJSON () { вернуть это . # id ; } toString () { вернуть это . # id ; } valueOf () { вернуть это . # id ; } }
У Julia есть неизменяемые составные типы данных. [13]
использование UUID "Представляет идентификатор пользователя." struct UserId id :: UUID end База.строка ( userId :: UserId ) = userId.id
В Kotlin есть «встроенные классы». [14]
/** * Представляет идентификатор пользователя. * * @property id Идентификатор пользователя. * @constructor Создает идентификатор пользователя. */ @JvmInline public value class UserId ( public val id : String ) { override fun toString () = id }
Ним имеет «отдельные типы». [15] [16]
## Представляет идентификатор пользователя. type UserId * = отдельная строка
Этот пример реализации PHP__toString()
реализует магический метод. [17]
Кроме того, он реализует JsonSerializable
интерфейс, который используется встроенной json_encode
функцией для сериализации класса в простую строку вместо составного типа данных . [18]
Класс объявляется с использованием final
ключевого слова modifier для предотвращения наследования. [19]
В PHP есть черты как способ повторного использования кода. [20]
/** * Представляет идентификатор пользователя. */ final class UserId implements JsonSerializable { use StronglyTypedIdentifier ; }/** * Предоставляет методы для использования со строго типизированными идентификаторами. */ trait StronglyTypedIdentifier { /** * Инициализирует новый экземпляр объекта UserId. * @param string $id Идентификатор пользователя. */ public function __construct ( public readonly string $id ) {} /** * Создает новый идентификатор пользователя. */ public static function new () : self { return new self ( bin2hex ( random_bytes ( 16 ))); } публичная функция jsonSerialize () : string { return $this -> id ; } публичная функция __toString () : string { return $this -> id ; } }
В Python есть классы данных, которые обеспечивают проверку равенства и могут быть сделаны неизменяемыми с помощью frozen
параметра. [21] Он переопределяет __str__
метод dunder. [22]
В этом примере реализации реализован статический метод, который можно использовать для инициализации нового экземпляра с помощью случайно сгенерированного универсального уникального идентификатора (UUID).
из dataclasses импорт dataclass импорт uuid@dataclass ( frozen = True ) class UserId : """Представляет идентификатор пользователя.""" id : uuid . UUID @staticmethod def new () -> Self : """Создать новый идентификатор пользователя.""" return __class__ ( uuid . uuid4 ()) def __str__ ( self ): возвращает str ( self . id )
У Python также есть NewType
язык программирования, который можно использовать для создания новых типов данных. [23]
от ввода import NewTypeUserId = NewType ( 'UserId' , int )
В Ruby есть классы данных, которые обеспечивают проверку равенства и являются неизменяемыми. [24] Он переопределяет встроенный to_s
метод.
В этом примере реализации реализован статический метод, который можно использовать для инициализации нового экземпляра с помощью случайно сгенерированного универсального уникального идентификатора (UUID).
требуется «securerandom» # Представляет идентификатор пользователя. UserId = Data . define ( :id ) do # Создать новый идентификатор пользователя. def self . create self . new ( SecureRandom . uuid ) end def self.empty self.new ( ' 00000000-0000-0000-0000-000000000000 ' ) end def to_s id конец конец
В Rust это можно сделать с помощью структуры кортежа, содержащей одно значение. [25] Этот пример реализации реализует черты Debug
[26] и PartialEq
[27] . Черта обеспечивает проверку равенства.PartialEq
// Представляет идентификатор пользователя. #[derive(Debug, PartialEq)] pub struct UserId ( String );
В Scala есть классы case, которые обеспечивают неизменность и проверку равенства. [28] Класс case запечатан, чтобы предотвратить наследование.
импорт java.util.UUID /** Представляет идентификатор пользователя. * * @constructor * Создает новый идентификатор пользователя. * @param id * Идентификатор пользователя. */ sealed case class UserId ( id : UUID ) object UserId : /** Инициализирует новый экземпляр класса UserId. */ def create (): UserId = UserId ( UUID . randomUUID ())
В Swift есть CustomStringConvertible
протокол, который можно использовать для предоставления собственного представления, используемого при преобразовании экземпляра в строку, [29] и Equatable
протокол, который обеспечивает проверку равенства. [30]
импортный фонд/// Представляет идентификатор пользователя. struct UserId : CustomStringConvertible , Equatable { private let id : UUID init ( _id : UUID ) { self.id = id } var description : String { return id . uuidString . нижний регистр } /// Создает новый идентификатор пользователя. static func new () -> Self { return Self ( UUID ()) } }
Zig имеет структуры [31] с константами, но по своей конструкции не имеет перегрузки операторов [32] и переопределения методов.
/// Представляет идентификатор пользователя. const UserId = struct { value : i32 , /// Инициализирует новый экземпляр структуры UserId. pub fn init ( value : i32 ) UserId { return UserId { . value = value }; } };