J'ai essayé de créer un objet de valeur en raison de la conception axée sur le domaine, mais c'était assez gênant, j'ai donc créé une classe parent. (Comme il est conçu pour le développement personnel afin d'accélérer le développement, nous ne garantissons pas qu'il puisse être utilisé tel quel dans le produit)
https://qiita.com/kichion/items/151c6747f2f1a14305cc C'est un objet avec les caractéristiques décrites dans.
Si vous l'écrivez en Ruby, ce sera un objet comme ↓. Cet exemple est un objet de valeur qui contient le nom de l'utilisateur. (Si vous voulez faire une définition légitime, il serait préférable de définir quelque chose comme ʻequal`, mais je ne l'utilise pas tellement, donc je ne l'ai pas défini maintenant.)
domain/user/name.rb
module Domain::User
class Name
attr_reader :first_name, :last_name
def initialize(first_name, last_name)
@first_name = first_name
@last_name = last_name
end
def update_first_name(first_name)
self.new(first_name, @last_name)
end
def update_last_name(last_name)
self.new(@first_name, last_name)
end
def fullname
"#{@last_name} #{@first_name}"
end
end
end
C'est pratique à utiliser, mais c'est un problème d'écrire quelques lignes de getters et de setters dans ce champ de routine. J'ai donc créé une classe parente qui les définit arbitrairement.
domain/base/value_object.rb
module Domain::Base
class ValueObject
attr_reader :changed_fields
FIELDS = []
class << self
#Définissez la méthode suivante new_date = date.update_month(11)
def attr_updater(*attrs)
attrs.map(&:to_sym).each do |defining_attr|
define_method("update_#{defining_attr}") do |defining_value|
values = attrs.map { |attribute| attribute == defining_attr ? defining_value : instance_variable_get("@#{attribute}")}
changed_fields = @changed_fields.include?(defining_attr) ? @changed_fields : @changed_fields + [defining_attr]
self.class.new(*values, changed_fields: changed_fields)
end
end
end
end
# NOTE
# -Fondamentalement, seuls les CHAMPS et les accesseurs sont définis du côté de l'objet de valeur.
# -initialize permet au parent d'utiliser cette classe d'objets.
# -Il est possible d'implémenter votre propre initialisation. Cependant, dans ce cas, seule l'initialisation de cette classe parente est utilisée du côté de l'objet de valeur, et l'utilisateur d'objet de valeur n'est pas autorisé à utiliser directement l'initialisation de cette classe.
# - changed_Les modifications telles que les champs sont effectuées uniquement en interne
# -Veillez à ce que les arguments d'initialisation de l'objet valeur lui-même soient aussi simples que possible
def initialize(*field_values, fields: self.class::FIELDS, changed_fields: [])
define_fields(fields, field_values)
@changed_fields = changed_fields
end
private
def define_fields(fields, field_values)
fields.zip(field_values).each do |field, field_value|
instance_variable_set("@#{field}", field_value)
end
end
end
end
En utilisant cela, la méthode originale peut être fournie par la méthode d'écriture suivante.
domain/user/name.rb
module Domain::User
class Name < ::Domain::Base::ValueObject
FIELDS = %I(first_name last_name)
attr_reader *FIELDS
attr_updater*FIELDS
def fullname
"#{@last_name} #{@first_name}"
end
end
end
Remarques
――Si vous utilisez trop de magie noire de la métaprogrammation, vous ne pourrez pas la suivre (que ce soit grep ou visuellement), nous n'avons donc pas défini de méthodes compliquées
――Vous pouvez automatiser ʻattr_reader, mais ʻattr_reader
ne pèse pas sur le lecteur, donc je suis la méthode d'écriture de base Ruby.
――Cette façon d'écrire indique implicitement que les arguments doivent être entrés dans l'ordre spécifié par FILED au moment de ʻinitialize, et je ne l'ai pas spécifié, mais je connais le problème moi-même, alors maintenant Il est évité par l'opération. --
changed_fields` a été créé comme vous le souhaitez parce que je voulais mettre à jour uniquement les champs qui ont été mis à jour lorsque la base de données a été mise à jour.
Recommended Posts