Maison >Java >javaDidacticiel >Analyse de code d'exemple d'ingénierie de projet Java
En fait, le « bon » et le « mauvais » dont nous parlons souvent sont une description de la qualité du code. « Bon » signifie généralement un code de haute qualité et « mauvais » signifie généralement un code de mauvaise qualité. Concernant la description de la qualité du code, en plus des descriptions relativement simples et grossières telles que « bon » et « mauvais », nous entendons souvent de nombreuses autres descriptions. Ces méthodes de description sont sémantiquement plus riches, plus professionnelles et plus détaillées. " N’importe quel imbécile peut écrire du code qu’un ordinateur peut comprendre. Les bons programmeurs écrivent du code que les humains peuvent comprendre. » Traduit en chinois : « N’importe quel imbécile peut écrire du code qu’un ordinateur peut comprendre. » « Les bons programmeurs peuvent écrire du code que les gens peuvent comprendre. » Il existe même une certification au sein de Google appelée Readability. Seuls les ingénieurs ayant obtenu cette certification sont qualifiés pour approuver la soumission du code par d'autres personnes lors de la révision du code. On voit à quel point la lisibilité du code est importante. Après tout, le nombre de fois que le code est lu dépasse de loin le nombre de fois qu’il est écrit et exécuté.
Je crois personnellement que la lisibilité du code devrait être l'un des indicateurs les plus importants pour évaluer la qualité du code. Lorsque nous écrivons du code, nous devons toujours nous demander si le code est facile à lire et à comprendre. De plus, la lisibilité du code affecte dans une large mesure la maintenabilité du code. Après tout, qu’il s’agisse de corriger des bugs ou de modifier et d’ajouter du code fonctionnel, la première chose que nous devons faire est de comprendre le code. Si vous ne comprenez pas bien le code, il est très probable que de nouveaux bugs soient introduits en raison d'une prise en compte insuffisante.
La lisibilité étant si importante, comment devrions-nous évaluer la lisibilité d'un morceau de code ? Nous devons vérifier si le code est conforme aux normes de codage, si le nom est significatif, si les commentaires sont détaillés, si la longueur de la fonction est appropriée, si la division des modules est claire, si elle répond à une cohésion élevée et un faible couplage, etc. Vous devriez également pouvoir sentir que du côté positif, il nous est difficile de donner une liste qui couvre tous les indicateurs d'évaluation. C'est aussi pourquoi nous ne pouvons pas quantifier la lisibilité. En fait, la revue de code est un bon moyen de tester la lisibilité du code. Si vos collègues peuvent facilement lire le code que vous avez écrit, cela signifie que la lisibilité de votre code est très bonne ; si vos collègues ont beaucoup de questions en lisant votre code, cela signifie que la lisibilité de votre code doit être améliorée
Maintenabilité maintenabilité Fait généralement référence à la capacité de modifier rapidement des bogues ou d'ajouter du code sans détruire la conception originale du code, sans apporter de nouveaux bogues, indiquant la bonne maintenabilité du code. Lorsqu'il s'agit de développement de codage, la soi-disant « maintenance » n'est rien d'autre que la correction de bugs, la modification de l'ancien code et l'ajout de nouveau code. Ce qu'on appelle « le code est facile à maintenir » signifie que le code peut être rapidement modifié ou ajouté sans détruire la conception originale du code ni introduire de nouveaux bogues. Ce qu'on appelle « le code n'est pas facile à maintenir » signifie que la modification ou l'ajout de code nécessite un grand risque d'introduire de nouveaux bogues et prend beaucoup de temps.
Principe d'ouverture-fermeture OCP (Principe d'ouverture-fermeture)
Principe de responsabilité unique SRP (Principe de responsabilité unique)
Principe d'inversion de dépendance DIP (Principe d'inversion de dépendance)
Principe de moindre connaissance LKP ( Principe de la moindre connaissance)) / Loi de Déméter
Principe de substitution de Liskov LSP (Principe de substitution de Liskov)
Principe de ségrégation d'interface ISP (Principe de ségrégation d'interface)
Principe de réutilisation de combinaison/agrégation CARP (Réutilisation composite/agrégat Principe)
Tout le monde doit être familier avec ces théories. Ce sont des lignes directrices lorsque nous écrivons du code développé selon ces principes a les caractéristiques d'une cohésion élevée et d'un faible couplage. principes pour mesurer la qualité de notre code.
Je crois que chaque ingénieur veut écrire du code de haute qualité et ne veut pas continuer à écrire du mauvais code qui ne se développe pas et qui est critiqué par les autres. Alors, comment pouvons-nous écrire du code de haute qualité ? Concernant ce qu'est un code de haute qualité, nous venons de parler des sept indicateurs d'évaluation les plus couramment utilisés et les plus importants. Par conséquent, se demander comment écrire du code de haute qualité équivaut à se demander comment écrire un code facile à maintenir, facile à lire, facile à développer, flexible, concis, réutilisable et testable. Mais écrire un bon code ne nécessite pas non plus. se produit du jour au lendemain, cela nécessite beaucoup de pratique et d'accumulation. Voici un bref exemple :
La pensée abstraite est la capacité de réflexion la plus importante pour nos ingénieurs, car la technologie logicielle est essentiellement un art abstrait. Nos ingénieurs doivent utiliser la pensée abstraite chaque jour pour analyser, résumer, synthétiser, juger et raisonner sur le domaine du problème, faisant ainsi abstraction de divers concepts, explorant la relation entre les concepts, puis réalisant des fonctions commerciales à l'aide de langages de programmation. le temps n'est pas à écrire du code, mais à trier les exigences, à clarifier les concepts et à acquérir une compréhension globale des exigences. La capacité d'abstraction nous fait ressentir, à moi et à mon équipe, les changements qualitatifs qu'elle nous apporte dans le codage et la conception.
Cas 1 : Export Excel asynchrone
En fait, la fonction d'export Excel est visible partout dans nos projets, surtout nos opérations espèrent exporter autant de données que possible en même temps afin de ne pas mettre trop de pression sur nos. system, pour le big data L'export des quantités s'effectue généralement de manière asynchrone. Pour une fonction aussi simple, comment doit-elle être abstraite ?
Écriture ordinaire :
public String exportXXX(参数) throws Exception { //业务实现 } public String exportXXX2(参数) throws Exception { //业务实现 }
Écriture abstraite :
Nous pouvons en fait considérer chaque exportation asynchrone comme une tâche asynchrone, et le contenu qui peut être exporté par chaque tâche est différent, donc l'exportation peut être abstraite Une méthode, chaque implémentation spécifique class implémente et exporte différents contenus, comme suit :
// export excel public interface IExcelExportTask { String export(BizCommonExportTask exportTask) throws Exception; } //样例实现类 XXXXExportTask implements IExcelExportTask { String export(BizCommonExportTask exportTask) throws Exception{ public String export(BizCommonExportTask exportTask) throws Exception { //组织数据筛选条件 TestReq queryReq = GsonUtils.toObject(exportTask.getInputParams(),TestReq.class); String fileName = String.format("%s%s%s", exportTask.getUploadFileName(),System.currentTimeMillis(),".xlsx"); String downUrl = excelService.uploadExcel(fileName, null, new Fetcher<PreOccupyModel>(PreOccupyModel.class) { //循环获取数据 @Override public List<TestModel> fetch(int pageNo, int pageSize) throws OspException{ TestQueryResp resp = testFethchLogic.fetchRecord(queryReq); return pageNo > resp.getPageNum() ? Collections.emptyList() :toExcelModel(resp); } }); return downUrl; } } public class XXXXExportTask1 implements IExcelExportTask { @Override public String export(BizCommonExportTask exportTask) throws OspException { TestQuery query = GsonUtils.toObject(exportTask.getInputParams(), TestQuery .class); String fileName = String.format("%s%s%s", exportTask.getUploadFileName(), System.currentTimeMillis(), ".xlsx"); return excelService.uploadExcel(fileName, null, new Fetcher<ExportItemModel>(TestModel.class) { @Override public List<TestModel> fetch(int pageNo, int pageSize) throws OspException { return XXXXLogic.queryExportItem(query, pageNo, pageSize); } }); } } //导出任务分发器 public class ExcelTaskDispacther extends ApplicationObjectSupport { public boolean dispacthTask(Long taskId) throws OspException { updateTaskStatus(exportTask,CommonExportStatus.CREATING,TransferExportStatus.CREATING,StringUtils.EMPTY); try { String beanName = getBeanName(); ExportTaskHandler exportTaskHandler = getApplicationContext().getBean(beanName , IExcelExportTask .class); if(exportTaskHandler == null) { log.warn(String.format("任务ID[%s]写入配置错误!", taskId)); return false; } updateTaskStatus(exportTask,CommonExportStatus.CREATE_SUCCESS,TransferExportStatus.CREATE_SUCCESS,StringUtils.EMPTY); log.info(String.format("任务ID[%s]RFID为[%s]处理成功", exportTask.getId(),rfid)); return true; } catch(BusiException ex) { log.info("任务ID[{}]失败,原因:{}", exportTask.getId(),ex.getMessage(),ex); updateTaskResult(); } catch(Exception ex) { log.info("任务ID[{}]失败,原因:{}", exportTask.getId(),ex.getMessage(),ex); updateTaskResult(); } return false; } }
Cas 2 : Notification système
À l'ère actuelle des microservices populaires, afin d'améliorer le débit du système, les responsabilités du système sont de plus en plus détaillées. Chaque module système doit interagir fréquemment. avec des données, donc pour des scénarios d'interaction de données complexes, tels que notre ordre de transfert, l'ordre de transfert doit interagir avec de nombreux systèmes pendant le processus d'annulation et a de nombreuses interactions avec les magasins, les entrepôts et les modules d'inventaire. Que devons-nous faire. ? Comment l'abstraire ? Ce qui suit est un exemple de code pour allouer des interactions avec divers systèmes
//接口定义 public interface BizNotificationHandler { /** * 抛异常会当失败处理 * 是否需要重试由BizNotificationStatus返回状态来决定 * @param bizNotification * @return * @throws OspException */ BizNotificationStatus handleNotification(BizNotification bizNotification) throws OspException; } //推送调拨差异数据给库存系统 public class SyncDiffToSimsAndBackQuotaHandler implements BizNotificationHandler { @Override public BizNotificationStatus handleNotification(BizNotification bizNotification) throws OspException { //业务逻辑实现 return BizNotificationStatus.PROCESS_SUCCESS; } } //占用库存 public class TransferOccupyInventoryHandler implements BizNotificationHandler { @Override public BizNotificationStatus handleNotification(BizNotification bizNotification) throws OspException { //业务实现 } } //在GPDC生成新条码 public class GpdcGenerateNewBarcodeHandler implements BizNotificationHandler { @Override public BizNotificationStatus handleNotification(BizNotification bizNotification) throws OspException { //业务代码实现 } }
En fait, lorsque nous interagissons avec d'autres systèmes, nous pouvons résumer chaque action d'interaction dans un événement de notification. Chaque fois que nous interagissons, écrivez un événement. les événements de notification suffisent.
Concernant le principe de réutilisation combinaison/agrégation, en effet, nous le rencontrons souvent au cours du processus de projet. Par exemple, dans le projet, nous gérons souvent divers documents, tels que. comme les bons de commande, les ordres de transfert, etc. Bon de réception, etc., et il y aura diverses vérifications pour chaque type de document Voyons d'abord un code pour l'ordre de construction et de transfert Comment le télécharger spécifiquement :
//接口定义 public interface TransferValidator { boolean validator(CreateTransferCtx ctx) throws OspException; } //接口实现1 public class W2sCrossPoQtyValidator implements TransferValidator { @Override public boolean validator(CreateTransferCtx ctx) throws OspException { //较验器代码实现 } //接口实现2 public class W2sStoreBarcodeSaleLimitValidator implements TransferValidator { @Override public boolean validator(CreateTransferCtx ctx) throws OspException { //较验器代码实现 } } //较验器组装 public class TransferValidators { public ValidatorChain newChain() { return new ValidatorChain(); } public class ValidatorChain { private final List<TransferValidator> validators = new ArrayList<>(); public ValidatorChain qtyValidator() { validators.add(qtyValidator); return this; } public ValidatorChain transferRouteCfgValidator() { validators.add(transferRouteCfgValidator); return this; } public ValidatorChain prodValidator() { validators.add(prodValidator); return this; } public ValidatorChain w2sWarehouseStoreValidator() { validators.add(w2sWarehouseStoreValidator); return this; } public ValidatorChain w2sStoreBarcodeSaleLimitValidator() { validators.add(w2sStoreBarcodeSaleLimitValidator); return this; } public ValidatorChain w2sAssignPoValidator() { validators.add(w2sAssignPoValidator); return this; } public ValidatorChain w2sCrossPoValidator() { validators.add(w2sCrossPoValidator); return this; } public ValidatorChain w2sCrossPoQtyValidator() { validators.add(w2sCrossPoQtyValidator); return this; } public ValidatorChain w2sCross4XupValidator() { validators.add(w2sCross4XupValidator); return this; } public ValidatorChain repeatLineValidator() { validators.add(repeatLineValidator); return this; } public ValidatorChain sstradeBarcodeValidator() { validators.add(sstradeBarcodeValidator); return this; } public ValidatorChain s2wWarehouseStoreValidator() { validators.add(s2wWarehouseStoreValidator); return this; } public boolean validator(CreateTransferCtx ctx) throws OspException { for (TransferValidator validator : validators) { if (!validator.validator(ctx)) { return false; } } return true; } } } //业务代码使用 public interface TransferCreator { boolean createOrder(CreateTransferCtx ctx) throws OspException; } public abstract class DefaultTransferCreator implements TransferCreator { @Override public boolean createOrder(CreateTransferCtx ctx) throws OspException { validator(ctx) //实现业务逻辑 } protected abstract boolean validator(CreateTransferCtx ctx) throws OspException; } //店仓调拨单 public class S2wRefundCreator extends DefaultTransferCreator { //较验器自由组装 @Override protected boolean validator(CreateTransferCtx ctx) throws OspException { return transferValidators.newChain() .qtyValidator() .transferRouteCfgValidator() .prodValidator() .validator(ctx); } }.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!