[JAVA] Une histoire qui pourrait être mise en œuvre proprement en utilisant le polymorphisme lorsque vous souhaitez exprimer deux types de données dans une table

Une histoire qui pourrait être mise en œuvre proprement en utilisant le polymorphisme lorsque vous souhaitez exprimer deux types de données dans une table

Aperçu

Parfois, j'ai créé un écran pour afficher deux types de données ensemble dans une table. À cette époque, j'ai pu l'implémenter proprement en utilisant le polymorphisme en utilisant une interface au lieu du branchement conditionnel. Je voudrais vous présenter les avantages du code actuel.

supposition

Environnement de développement

spécification

  1. Affichez l'historique des achats de produits et l'historique des contrats de service d'abonnement sur Amazon
  2. Je souhaite afficher dans l'ordre chronologique indépendamment de l'historique d'achat du produit ou de l'historique du contrat du service d'abonnement.
  3. Afficher la date d'achat, le nom du produit, le prix unitaire, le nombre d'achats, le sous-total
  4. Pour les contrats d'abonnement, affichez la date de début du contrat, le nom du service, le prix unitaire, les mois du contrat et le sous-total.
  5. Les contrats d'abonnement bénéficient de réductions lorsqu'ils sont contractés annuellement

image d'écran

スクリーンショット 2019-06-24 12.38.30.png

2 types d'exemples de code

L'ensemble du code peut être trouvé sur GitHub. Veuillez me pardonner bien qu'il puisse y avoir une pénurie parce que je vais l'expliquer brièvement.

Exemple d'utilisation du branchement conditionnel

Je vais vous donner un programme extrêmement sale, mais j'ai implémenté l'exemple en utilisant le branchement conditionnel comme suit.

  1. Obtenez des données de l'historique des achats et de l'historique des contrats et stockez-les dans un tableau associatif
  2. Extrayez la clé du tableau associatif et la date d'achat / date du contrat, et générez une liste dans laquelle les ID sont triés par ordre croissant de date.
  3. Afficher l'historique des achats et l'historique des contrats à l'écran dans l'ordre de la liste des ID

monomorphism/PurchaseController.java


@Controller
@RequestMapping("monomorphism/purchase")
public class PurchaseController {
    //La description de DI de service est omise.

    @GetMapping("list/{memberId}")
    public ModelAndView listByBadDto(@PathVariable Integer memberId) {
        List<Contract> memberContracts = purchaseHistoryQueryService.getMemberContracts(memberId);
        List<Purchase> memberPurchases = purchaseHistoryQueryService.getMemberPurchases(memberId);

        ModelAndView modelAndView = new ModelAndView("monomorphism/complex");
        // c-{id}Clé de format et carte de contrat
        Map<String, Contract> contractMap = memberContracts.stream().collect(Collectors.toMap(c -> "c-" + c.id, c -> c));
        modelAndView.addObject("memberContracts", contractMap);

        // p-{id}Formater la clé et la carte d'achat
        Map<String, Purchase> purchaseMap = memberPurchases.stream().collect(Collectors.toMap(p -> "p-" + p.id, p -> p));
        modelAndView.addObject("memberPurchases", purchaseMap);

        //Générer l'identifiant et la date d'achat Cartographier et trier par date d'achat
        Map<String, LocalDate> contractDateMap = contractMap.entrySet().stream()
                .collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().beginDate));
        Map<String, LocalDate> purchaseDateMap = purchaseMap.entrySet().stream()
                .collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().purchasedDate));

        Map<String, LocalDate> idMap = new HashMap<>();
        idMap.putAll(contractDateMap);
        idMap.putAll(purchaseDateMap);
        List<String> ids = idMap.entrySet().stream()
                .sorted(Comparator.comparing(Map.Entry::getValue))
                .map(Map.Entry::getKey)
                .collect(Collectors.toList());

        modelAndView.addObject("ids", ids);
        return modelAndView;
    }
}

monomorohism/complex.html


<table class="uk-table">
    <thead>
        <tr>
            <th>Date d'achat</th>
            <th>Nom du produit acheté</th>
            <th>Prix unitaire</th>
            <th>Nombre d'achats</th>
            <th>total</th>
        </tr>
        </thead>
        <tbody>
        <tr th:each="id: ${ids}">
            <th:block th:if="${id.startsWith('c-')}" th:with="contract = ${memberContracts.get(id)}">
                <td th:text="${contract.beginDate}"></td>
                <td th:text="${contract.service.name}"></td>
                <td th:text="|${contract.service.priceByUnitMonth}Cercle/${contract.service.unitMonths}mois|"></td>
                <td th:text="|${contract.months}mois|"></td>
                <td th:text="|${contract.service.priceByUnitMonth / contract.service.unitMonths * contract.months - contract.service.yearlyDiscount}Cercle|"></td>
            </th:block>
            <th:block th:if="${id.startsWith('p-')}" th:with="purchase = ${memberPurchases.get(id)}">
                <td th:text="${purchase.purchasedDate}"></td>
                <td th:text="${purchase.commodity.name}"></td>
                <td th:text="|${purchase.commodity.unitPrice}Cercle|"></td>
                <td th:text="|${purchase.amount}Pièces|"></td>
                <td th:text="|${purchase.commodity.unitPrice * purchase.amount}Cercle|"></td>
            </th:block>
        </tr>
    </tbody>
</table>

Le contrôleur et la vue sont complexes, même si l'historique des contrats et l'historique des achats ne sont affichés que dans une liste.

Exemple utilisant le polymorphisme

Dans l'exemple utilisant le polymorphisme, il a été implémenté comme suit.

  1. Convertissez les données d'achat et les données de contrat obtenues de la base de données en une classe de type d'historique d'achat
  2. Triez les données de type d'historique d'achat par ordre de date d'achat et affichez-les à l'écran

polymorphism.PurchaseService.java


@Service
public class PurchaseService {
    //La description de DI du référentiel est omise

    public List<PurchaseHistory> getMemberPurchaseHistory(Integer memberId) {
        //Acquérir des données d'achat de produit et les convertir en une classe d'historique d'achat de produit qui implémente le type d'historique d'achat
        List<Purchase> purchases = purchaseRepository.findByMemberId(memberId);
        Stream<CommodityPurchaseHistory> commodityPurchaseHistoryStream = purchases.stream().map(CommodityPurchaseHistory::new);

        //Acquérir des données de contrat de service et les convertir en une classe d'historique d'achat de service qui implémente le type d'historique d'achat
        List<Contract> contracts = contractRepository.findByMemberId(memberId);
        Stream<ServicePurchaseHistory> contractHistoryStream = contracts.stream().map(ServicePurchaseHistory::new);

        //Combinez des listes de types d'historique d'achat et triez par date d'achat
        return Stream.concat(commodityPurchaseHistoryStream, contractHistoryStream)
                .sorted(Comparator.comparing(PurchaseHistory::purchasedDate))
                .collect(Collectors.toList());
    }
}

polymorphism.PolyPurchaseController.java


@Controller
@RequestMapping("polymorphism/purchase")
public class PolyPurchaseController {
    //La description de DI de service est omise.
    @GetMapping("list/{memberId}")
    public ModelAndView getInterface(@PathVariable("memberId") Integer memberId) {
        List<PurchaseHistory> memberPurchaseHistories = purchaseService.getMemberPurchaseHistory(memberId);
        ModelAndView modelAndView = new ModelAndView("polymorphism/list");
        modelAndView.addObject("memberPurchaseHistories", memberPurchaseHistories);
        return modelAndView;
    }
}

La description de la vue est très rafraîchissante car elle n'appelle que la méthode de type historique des achats.

polymorphism/list.html


<table class="uk-table">
    <thead>
        <th>Date d'achat</th>
        <th>Nom du produit acheté</th>
        <th>Prix unitaire</th>
        <th>Nombre d'achats</th>
        <th>total</th>
    </thead>
    <tbody>
        <tr th:each="purchaseHistory : ${memberPurchaseHistories}">
            <td th:text="${purchaseHistory.purchasedDate()}"></td>
            <td th:text="${purchaseHistory.purchasedCommodityName()}"></td>
            <td th:text="${purchaseHistory.unitPrice()}"></td>
            <td th:text="${purchaseHistory.amount()}"></td>
            <td th:text="${purchaseHistory.subtotal()}"></td>
        </tr>
    </tbody>
</table>

à la fin

Que vous utilisiez le polymorphisme ou non, il est préférable de conserver les calculs et les conditions dans un programme côté serveur.

Je pense que la plupart des concepteurs qui collaborent avec nous n'ont aucune connaissance du moteur de template de Java, donc je pense qu'il est préférable de garder le fichier Html simple. Si vous concevez et programmez en tenant compte du type de technologie dont disposent vos collègues et du meilleur type de répartition des rôles, vous pouvez aborder le succès de toute l'équipe de développement.

En plus de cela, si vous utilisez le polymorphisme, vous pouvez écrire un programme avec une bonne visibilité en réduisant les instructions if du programme côté serveur.

Recommended Posts

Une histoire qui pourrait être mise en œuvre proprement en utilisant le polymorphisme lorsque vous souhaitez exprimer deux types de données dans une table
Je veux que vous racontiez que l'erreur a été résolue lorsque vous avez poignardé le chargeur dans le coin de la tête
[Swift] Lorsque vous voulez savoir si le nombre de caractères dans String correspond à un certain nombre ...
Une collection de modèles dont vous voulez être conscient pour ne pas compliquer le code
Un mémorandum lorsque vous souhaitez voir les données acquises par Jena & SPARQL pour chaque variable.
Comment créer une paire de clés d'ecdsa dans un format lisible par Java
Comment mettre en œuvre un diaporama en utilisant Slick in Rails (un par un et plusieurs par un)
Lorsque vous souhaitez notifier une erreur quelque part lors de l'utilisation de graphql-spring-boot avec Spring Boot
Comment créer une combinaison unique de données dans la table intermédiaire des rails
Une histoire que les personnes qui ont fait iOS solidement peuvent être accro à la mise en œuvre de Listener lors du passage à Android