La conversion entre la classe Form qui reçoit la valeur d'entrée et l'entité est difficile, j'ai donc pensé à quatre solutions.
1.Faites de chaque valeur d'entrée un argument de la méthode Service 2. Créez des objets en unités significatives 3. Transformez la méthode Service en une classe Form 4. Faites de l'argument de service une interface
Je pense que les solutions qui pourraient être utilisées sont 2 et 4. Cette fois, nous l'avons résolu en 4 sur la base de la culture interne.
Je convertissais avec Entity pour la persistance dans la classe Form comme suit.
PurchaseForm.java
@Data
public class PurchaseForm {
@NotNull
private Integer commodityId;
@NotNull
private Integer count;
/**
*Générer l'entité en fonction de la valeur d'entrée
*/
public Purchase toEntity() {
//réduction
}
}
S'il s'agit d'une simple conversion, il n'y a aucun problème, mais si c'est le modèle suivant, il mourra.
À mesure que la quantité de code dans le programme à convertir en Entité augmente, la visibilité du code source se détériore. Surtout lorsque vous essayez de générer une classe enfant de la classe à générer, c'est assez douloureux. Dans les projets dans lesquels je suis impliqué, je compte souvent sur AUTO INCREMENT pour la numérotation de la clé primaire, il est donc inévitablement nécessaire de compléter la clé primaire et la clé externe avec la classe Service. Une préoccupation est divisée en plusieurs classes, telles que l'initialisation d'une pièce avec Form et l'initialisation du reste avec la classe Service, et le code source devient difficile à suivre.
PurchaseForm.java
@Data
public class PurchaseForm {
//réduction
/**
*Générer l'entité en fonction de la valeur d'entrée
*/
public Purchase toEntity() {
//Cette
//Cette
//Mais
//Moi
//Tsu
//Chi
//Ya
//Longue
//je
//Quand
//Conclusion
//Structure
//Un
//Et al.
//je
}
}
Si vous avez besoin d'un objet persistant dans l'argument jusqu'à présent, vous ne devez plus le convertir dans la classe Form.
PurchaseForm.java
@Data
public class PurchaseForm {
//réduction
/**
*Générer l'entité en fonction de la valeur d'entrée
*Si vous prenez un grand nombre d'objets persistants comme arguments, vous vous demandez si vous devez créer une entité ici.
*/
public Purchase toEntity(Hoge hoge, Fuga Futa, ... etc) {
//réduction
}
}
J'ai essayé mais c'est douloureux. Car à mesure que la valeur d'entrée de Form augmente, le nombre d'arguments augmente.
PurchaseController.java
@Controller
@RequireArgsConstructor
public class PurchaseController {
public final PurchaseService purchaseService;
public ModelAndView create(@ModelAttribute @Valid PurchaseForm form, BindingResult result) {
// check
// Ah...!
purchaseService.purchase(form.input1, form.input2, form.input3, form.input4, form.input5,...);
}
}
PurchaseController.java
@Controller
@RequireArgsConstructor
public class PurchaseController {
public final PurchaseService purchaseService;
public ModelAndView create(@ModelAttribute @Valid PurchaseForm form, BindingResult result) {
// check
purchaseService.purchase(new Hoge(form.input1, form.input2), new Fuga(form.input3, form.input4, form.input5),...);
}
}
L'avantage est que vous pouvez préconditionner l'objet argument pour garantir l'intégrité de la valeur. Les conditions préalables sont vérifiées dans le constructeur.
C'est très simple, mais c'est un très mauvais modèle! Il est difficile pour la direction de dépendance d'être Form ← Service. Le formulaire est étroitement associé aux spécifications de l'écran, je ne veux donc pas que la logique métier dépende du formulaire. Il est étrange que la classe Service doive être modifiée car les spécifications de l'écran ont changé même si la logique métier n'a pas changé.
PurchaseController.java
@Controller
@RequireArgsConstructor
public class PurchaseController {
public final PurchaseService purchaseService;
public ModelAndView create(@ModelAttribute @Valid PurchaseForm form, BindingResult result) {
// check
// Fuck...!
purchaseService.purchase(form);
}
}
Cela a été résolu avec le quatrième plan.
Tout d'abord, j'ai défini l'interface de service et d'argument dans un package proche du domaine.
PurchaseService.java
@Service
public class PurchaseService {
public void purchase(PurchaseRequest request) {}
}
PurchaseRequest.java
public interface PurchaseRequest {
String getInput1();
Integer getInput2();
// etc...
}
Ensuite, j'ai écrit la validation de valeur dans une autre classe d'implémentation.
PurchaseForm.java
public class PurchaseForm implements PurchaseRequest {
@NotEmpty
private String input1;
@NotNull
private Integer input2;
public String getInput1() {
return input1;
}
public Integer getInput2() {
return input2;
}
}
L'intérêt de cette méthode d'implémentation est qu'elle déclare la valeur utilisée dans la classe Service au niveau de la couche proche du domaine, elle résiste donc aux changements côté écran. Bien sûr, si les entrées et les sorties changent en tant que concept commercial, elles doivent être revues, mais certaines différences peuvent être contrôlées côté écran.
Mieux encore, je pense qu'il est bon de lier la valeur d'entrée de l'écran au type défini côté domaine. Je pense que c'est souvent considéré comme la solution optimale. Ce qui précède est la solution que nous avons apportée dans notre projet en l'absence d'une culture d'implémentation de la validation sur des entités côté domaine, ou de capture et d'implémentation sémantique de types valeur.
Après cela, j'ai décidé de créer une API pour calculer le prix d'achat en fonction des informations sur les produits achetés et la quantité. Si vous définissez une méthode appelée PurchaseService # CalculatePrice (CalculatePriceRequest)
et laissez PurchaseRequest
hériter deCalculatePriceRequest
, vous pouvez facilement calculer le prix d'achat même avec un argument de type PurchaseRequest
. C'est vrai, puisqu'il y a des informations sur le produit et la quantité dans la demande d'achat de produit, il est tout à fait naturel de pouvoir calculer le prix d'achat sur la base de ces informations.
Je fais beaucoup d'essais et d'erreurs, mais je pense que je devrais être en mesure d'augmenter la main de la méthode de montage en analysant les modèles qui ont fonctionné ou qui n'ont pas fonctionné. En particulier, je développe souvent des applications WEB, j'aimerais donc réfléchir à différentes IO avec l'écran.
Recommended Posts