La logique d'une seule entité doit définir le comportement de l'entité, mais je ne sais pas où écrire le traitement pour la liste ou l'ensemble d'entités. J'ai résumé le contenu que j'ai étudié pour résoudre une telle hésitation.
J'ai souvent écrit des traitements pour des listes et des ensembles d'entités en service et de contrôleur.
HogeController.java
@Controller
public class HogeController {
private final HogeService service;
HogeController(HogeService service) {
this.service = service;
}
@RequestMapping("hoge")
public String xxx(Model model) {
List<ShoppingCartItem> cartItems = new ArrayList<>();
Integer total = cartItems.stream().mapToInt(ShoppingCartItem::subtotal()).sum();
model.addAttribute("total", total);
return "hoge/hoge";
}
}
Je pense que c'est bien. Cependant, si vous écrivez ce processus dans le contrôleur, lorsque vous souhaitez effectuer le même processus dans un autre contrôleur, le code sera probablement copié et la maintenance sera difficile lorsque des modifications sont apportées à la logique. Est visible.
Par conséquent, si vous créez une classe qui représente un ensemble comme indiqué ci-dessous, vous pouvez limiter la logique à un seul endroit.
ShoppingCartItems.java
public class ShoppingCartItems {
private List<ShoppingCartItem> items = new ArrayList<>();
public void addItem(ShoppingCartItem item) {
items.add(item);
}
public Integer total() {
return items.stream().mapToInt(ShoppingCartItem::subtotal()).sum();
}
}
Vous avez maintenant une méthode pour calculer le montant total dans une classe. Cependant, cela n'est toujours pas pratique. En effet, vous ne pouvez pas récupérer chaque ShoppingCartItem. ~~ Mort cérébrale ~~ Il est normal de définir Getter, mais voici quelques techniques utiles.
Il existe une instruction for étendue en tant que syntaxe que vous utiliserez pour récupérer chaque ShoppingCartItem. Ce serait bien si vous pouviez l'appeler ainsi!
ShoppingCartItems shoppingCartItems = new ShoppingCartItems();
for (ShoppingCardItem item : shoppingCartItems) {
// doSomething
}
Pour y parvenir, il est préférable d'implémenter l'interface ʻIterable
ShoppingCartItems.java
public class ShoppingCartItems implements Iterable<ShoppingCartItem> {
private List<ShoppingCartItem> items = new ArrayList<>();
//réduction
@Override
public Iterator<Asking> iterator() {
return items.iterator();
}
@Override
public void forEach(Consumer<? super Asking> action) {
items.forEach(action);
}
@Override
public Spliterator<Asking> spliterator() {
return items.spliterator();
}
}
Pour les trois méthodes qui doivent être implémentées dans l'interface Iterable, vous pouvez appeler la méthode du champ «articles» de la classe de collection contenue dans la classe. Vous pouvez maintenant écrire une instruction for étendue.
Je veux écrire comme ça.
HogeController.java
@Controller
public class HogeController {
@GetMapping("hoge")
public String hoge(Model model) {
model.addAttribute("shoppingCartItems", new ShoppingCartItems());
return "hoge";
}
}
hoge.jsp
<c:forEach items="${shoppingCartItems}" var="shoppingCartItem">
<%-- do something --%>
</c:forEach>
En conclusion, sans utiliser JSTL. Seules les variables suivantes peuvent être définies sur l'attribut items dans la balise JSTL forEach.
Cette limite est assez stricte. Puisque je travaille avec des listes cette fois, je pense que je vais implémenter le type Collection, mais je voulais personnellement éviter le type Collection car il existe de nombreuses méthodes inutiles. Donc, cette fois, j'ai implémenté le type Iterator en supposant que la boucle ne tourne qu'une seule fois.
ShoppingCartItems.java
public class ShoppingCartItems implements Iterable<ShoppingCartItem>, Iterator<ShoppingCartItem> {
private List<ShoppingCartItem> items = new ArrayList<>();
//réduction
private int cursor = 0;
@Override
public boolean hasNext() {
if (cursor < items.size()) {
return true;
}
return false;
}
@Override
public ShoppingCartItem next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
return items.get(cursor++); //Si vous ne l'incrémentez pas, il bouclera indéfiniment ☆ 彡
}
}
Vous pouvez maintenant spécifier une instance de la classe ShoppingCartItems dans l'attribut items de la balise JSTL forEach.
Vous pouvez l'utiliser en définissant la méthode de flux de champ d'éléments comme méthode de délégation à ce ShoppingCartItems. Si vous avez d'autres méthodes dont vous avez besoin, vous pouvez définir une méthode de délégation dans cette classe et elle sera prête à être utilisée. Cependant, nous vous déconseillons de définir des méthodes qui effectuent des opérations inutiles dans votre logique métier.
ShoppingCartItems.java
public Stream<ShoppingCartItem> stream() {
return items.stream();
}
En premier lieu, le but de la création d'une classe de gestion des collections est d'empêcher la falsification de la collection et d'augmenter le degré de cohésion. Si vous définissez trop de méthodes, cela ne servira pas votre objectif. Avant de définir une méthode, assurez-vous que vous en avez vraiment besoin.
Je pense qu'il est courant d'écrire des opérations sur des ensembles, en particulier des opérations liées à la logique métier, dans la classe Service. À l'avenir, j'aimerais envisager de définir une classe qui a un ensemble en tant que champ comme un moyen de confiner la logique métier de l'ensemble à un seul endroit.
Recommended Posts