DDD学习使用

简介

DDD(Domain-Driven Design):领域驱动设计
Eric Evans “领域驱动设计之父”
DDD不是架构,而是一种方法论(Methodology)微服务架构从一出来就没有很好的理论支撑如何合理的划分服务边界,人们常常为服务要划分多大而争吵不休

分层架构

DDD中 四层架构 表现层,应用层、领域层和基础层
  四层中的应用层是对三层架构中领域层进行进一步拆分。但是无论怎么分层,业务逻辑永远在领域层。
  三层架构:
    表现层(Contrtoller):负责向用户展示信息和接收用户的指令。需要负责处理展示逻辑,比如用户通过我们的系统进行信用卡还款,系统会返回三个状态未申请,处理中,处理完成。表面层需要根据这个状态给用户返回不同的页面,根据这三个不同的状态,向用户展示不同的中文说明。
    领域层(Service):负责表达业务逻辑,是整个系统的核心层。比如信用卡还款服务。
    持久层(DAO):提供数据查询和存储服务,包括按照状态查询信用卡。
  四层架构:
    表现层(Resources):同三层架构表现层。
    应用层(Application):定义软件要完成的任务,不包含业务逻辑,而是协调,比如受理用户请求的任务。负责非
    业务逻辑(批量删除、修改等)
    领域层(Domain):同三层架构领域层。
    基础层(Infrastucture):为各层提供通用的技术能力。为领域层提供数据和文件存储

项目包结构

在这里插入图片描述

基本概念

实体

身份标识(唯一标识):管理实体生命周期,如果没有唯一的身份标识,就无法追踪实体的状态变更,也就无法正确保证实体从创建、更改到消亡的生命过程。
属性
基本属性:通过基本类型定义的属性,如整型、布尔型、字符串类型等等
组合属性:通过自定义类型来定义的属性,比如类别Category,重量(Weight),单价(Price),自定义类型一般是指值类型
领域行为
变更状态的领域行为
自给自足的领域行为
互为协作的领域行为

@Entity
@Table(name = "t_sup_record",indexes = {@Index(name = "idx_t_sup_record1", columnList = "sp_type")}
)
public class SuperviseRecord extends ExBizEntity{@Column(length=10,nullable=false)private String spType;@OneToMany(mappedBy="supRecord",fetch= FetchType.EAGER,cascade= CascadeType.REMOVE,orphanRemoval=true)@OrderBy("createTime")private Set<SupRecordProcess> processes=new LinkedHashSet<>();public SuperviseRecord() {}public String getSpType() {return spType;}public Set<SupRecordProcess> getProcesses() {return processes;}
}

值对象

通常作为实体的属性而存在,在领域建模时,应该优先考虑使用值对象来建模而不是实体对象。因为值对象没有唯一标识,具备不可变性,是线程安全的,不用考虑并发访问带来的问题。值对象比实体更容易维护,更容易测试,更容易优化,也更容易使用。

@Embeddable
public class SuperviseRecordCreateInfo {
@JoinColumn(foreignKey=@ForeignKey(value=ConstraintMode.NO_CONSTRAINT))private SpecialSuperviseInfo specialSupInfo;@OneToOne(cascade=CascadeType.ALL,orphanRemoval=true)@JoinColumn(foreignKey=@ForeignKey(value=ConstraintMode.NO_CONSTRAINT))private NormalSuperviseInfo normalSupInfo;@OneToOne(cascade=CascadeType.ALL,orphanRemoval=true)@JoinColumn(foreignKey=@ForeignKey(value=ConstraintMode.NO_CONSTRAINT))private DisputeRecord disputeRecord;public SuperviseWork getSpWork() {return spWork;}public String getCreateOrgType() {return createOrgType;}public String getSpType() {return spType;}public SpecialSuperviseInfo getSpecialSupInfo() {return specialSupInfo;}public NormalSuperviseInfo getNormalSupInfo() {return normalSupInfo;}public DisputeRecord getDisputeRecord() {return disputeRecord;}public SuperviseRecordCreateInfo() {super();}public SuperviseRecordCreateInfo(SuperviseWork spWork, String createOrgType,SpecialSuperviseInfo specialSupInfo) {super();this.createOrgType = createOrgType;this.spType = SPTYPE_SPECIAL;this.spWork = spWork;this.specialSupInfo = specialSupInfo;}public SuperviseRecordCreateInfo(String createOrgType, SuperviseWork spWork,NormalSuperviseInfo normalSupInfo) {super();this.spType = SPTYPE_NORMAL;this.createOrgType = createOrgType;this.spWork = spWork;this.normalSupInfo = normalSupInfo;}//为 矛盾纠纷 构建public SuperviseRecordCreateInfo(String createOrgType, SuperviseWork spWork,DisputeRecord disputeRecord) {super();this.spType = SPTYPE_DISPUTE;this.createOrgType = createOrgType;this.spWork = spWork;this.disputeRecord = disputeRecord;}}

聚合根

在 Domain-Driven Design Reference 中,Eric Evans 阐释了何谓聚合模式:“将实体和值对象划分为聚合并围绕着聚合定义边界。选择一个实体作为每个聚合的根,并允许外部对象仅能持有聚合根的引用。作为一个整体来定义聚合的属性和不变量(Invariants),并将执行职责(Enforcement Responsibility)赋予聚合根或指定的框架机制。”
在项目中一个实体就是一个聚合根,实体与聚合根没有明显界限

@Entity
@Table(name="T_SUP_RECORD",indexes={@Index(name="idx_T_SUP_RECORD1",columnList="sp_work_id"),@Index(name="idx_T_SUP_RECORD2",columnList="spType")}
)
public class SuperviseRecord extends ExBizEntity {private SuperviseRecordCreateInfo createInfo;//创建信息private SuperviseRecordFinishInfo finishInfo;//办结信息@OneToMany(mappedBy="createInfo.supRecord",fetch=FetchType.EAGER,cascade=CascadeType.REMOVE,orphanRemoval=true)@OrderBy("createTime")private Set<SupRecordProcess> processes=new LinkedHashSet<>();@OneToMany(fetch=FetchType.EAGER,cascade=CascadeType.ALL,orphanRemoval=true)@JoinColumn(name="sup_record_id",nullable=false,foreignKey=@ForeignKey(value=ConstraintMode.NO_CONSTRAINT))@OrderBy("orderNo")private Set<SupRecordProcessLeaderInstruction> leaderInstrs = new LinkedHashSet<>();public SuperviseRecordCreateInfo getCreateInfo() {return createInfo;}public SuperviseRecordFinishInfo getFinishInfo() {return finishInfo;}public Set<SupRecordProcess> getProcesses() {return processes;}public Set<SupRecordProcessLeaderInstruction> getLeaderInstrs() {return leaderInstrs;}public SuperviseRecord() {super();}public SuperviseRecord(OperateInfo operateInfo, SuperviseWorkCategory spCategory, String cmpRecordId,SpecialSupExchCfxflzStatusInfo cfxfzlStatus, String fromSource, SysDataSimpleValObj category) {super();this.setCreateInfo(operateInfo);SpecialSuperviseInfo specialSupInfo=new SpecialSuperviseInfo(cmpRecordId, spCategory,fromSource,category);this.createInfo = new SuperviseRecordCreateInfo(spCategory.getSpWork(), operateInfo.getOperator().getOrgType(),specialSupInfo);this.finishInfo = new SuperviseRecordFinishInfo(spCategory.getSpWork().getSetting().getFinishJudge(),cfxfzlStatus);}public SuperviseRecord(OperateInfo operateInfo, NormalSuperviseInfo normalSupInfo, SuperviseWork spWork) {super();this.setCreateInfo(operateInfo);this.createInfo = new SuperviseRecordCreateInfo(operateInfo.getOperator().getOrgType(), spWork, normalSupInfo);this.finishInfo = new SuperviseRecordFinishInfo();}public SuperviseRecord(OperateInfo operateInfo, DisputeRecord disputeRecord, SuperviseWork spWork) {super();this.setCreateInfo(operateInfo);this.createInfo = new SuperviseRecordCreateInfo(operateInfo.getOperator().getOrgType(), spWork, disputeRecord);this.finishInfo = new SuperviseRecordFinishInfo(spWork.getSetting().getFinishJudge());}/********************************************开始领域业务方法***********************************************/public boolean updateFinishInfo(OperateInfo operateInfo, SuperviseRecordFinishInfo finishInfo) {this.lastUpdateDate = operateInfo.obtainNotNullOperateTime();boolean finishStatusTransfered=this.finishInfo.updateFinishInfo(operateInfo,finishInfo.getCloseCaseStatus(),finishInfo.getCloseCaseStatusDate(),finishInfo.getDefuseStatus(),finishInfo.getDefuseStatusDate(),finishInfo.getDefuseReportStatus(), finishInfo.getDefuseReportStatusDate(),finishInfo.getDefuseAuditStatus(),finishInfo.getDefuseAuditStatusDate());if(!finishStatusTransfered) return false;return true;}public void onBackflow(OperateInfo operateInfo) {this.lastUpdateDate = operateInfo.obtainNotNullOperateTime();SuperviseWork spWork = this.getCreateInfo().getSpWork();this.finishInfo.updateFinishJudge(spWork.getSetting().getFinishJudge());this.finishInfo.resetFinishStatusAfterBackFlow();}public void updateLeaderInstructions(OperateInfo operateInfo, Collection<SupRecordProcessLeaderInstruction> leaderInstrs){List<SupRecordProcessLeaderInstruction> oldLeaderInstructions = this.getPartyIdToLeaderInstructions(operateInfo.obtainOperateOrgId());Map<String,SupRecordProcessLeaderInstruction> existsLI=Optional.ofNullable(oldLeaderInstructions).orElse(new ArrayList<>()).stream().collect(Collectors.toMap(d->d.getId(), d->d,(d1,d2) -> d2));this.leaderInstrs.removeAll(oldLeaderInstructions);if (CollectionUtils.isEmpty(leaderInstrs)) return;for (SupRecordProcessLeaderInstruction lI : leaderInstrs) {SupRecordProcessLeaderInstruction newlI=existsLI.get(lI.getId());if(newlI==null) {newlI=lI;}else {newlI.updateLeaderInstruction(operateInfo,lI.getParty(),lI.getLeader(),lI.getContent(),lI.getOrderNo());}this.leaderInstrs.add(newlI);}}public SupRecordProcess createSupRecordProcessOfPartyPrc(OperateInfo operateInfo,SupRecordProcessSendRel supSendRel) {SupRecordProcess partyPrc=new SupRecordProcess(operateInfo, this, supSendRel.getParty());this.getProcesses().add(partyPrc);return partyPrc;}public boolean hasProcessed() {boolean result = false;for(SupRecordProcess prc:this.processes) {if(prc.getHandleInfo()!=null && prc.getHandleInfo().getProcessDate()!=null) {result=true;break;}for(SupRecordProcessSendRel sr:prc.getSendRels()) {if(sr.isSendedStatus()) {result = true;break;}}}return result;}}

在这里插入图片描述

工厂

DDD要求聚合内所有对象保证一致的生命周期,这往往会导致创建逻辑趋于复杂。为了减少调用者的负担,同时也为了约束生命周期,通常都会引入工厂来创建聚合
没有使用,项目中不需要

资源库(Repository)

资源库是对数据访问的一种业务抽象,使其具有业务意义。利用资源库抽象,就可以解耦领域层与外部资源,使领域层变得更为纯粹,能够脱离外部资源而单独存在。

资源库的设计原则:一个聚合对应一个资源库
接口与模型定义在一个包下

public interface SuperviseRecordRepository {SuperviseWorkCategoryParty getSuperviseWorkCategoryPartyById(String id);SuperviseWorkCategory getSuperviseWorkCategoryById(String id);SuperviseWork getSuperviseWorkById(String id);
}

实现定义在Infrastructure包下

@Repository
public class SuperviseRecordRepositoryJpaHibernate extends JpaHibernateRepositoryimplements SuperviseRecordRepository {@Overridepublic SuperviseWorkCategoryParty getSuperviseWorkCategoryPartyById(String id) {return this.getSession().find(SuperviseWorkCategoryParty.class,id);}@Overridepublic SuperviseWorkCategory getSuperviseWorkCategoryById(String id) {return this.getSession().find(SuperviseWorkCategory.class,id);}@Overridepublic SuperviseWork getSuperviseWorkById(String id) {return this.getSession().find(SuperviseWork.class,id);}
}

领域服务(Domain Service)

当存在下面其中的一种情况时,需要考虑引入领域服务

当存在聚合为了控制边界,并不会直接与别的聚合协作。
当业务系统中,有一些领域行为不适合放在任一聚合中,它们要么不需要聚合自身已知携带的数据,或者存在与聚合截然不同的变化方向。
当聚合需要同基础设施进行交互协作。

领域服务的特征

领域行为与状态无关
领域行为需要多个聚合参与协作,目的是使用聚合内的实体和值对象编排业务逻辑
领域行为需要与访问包括数据库在内的外部资源协作

@Service
@Transactional
public class SupRecordDomainService extends JpaBaseQueryService {public SuperviseWork saveSpecialSuperviseWork(Object ...) {//业务逻辑return null;}
}

领域事件(Domain Event)

领域事件是领域专家所关心的发生在领域中的一些事件。

主要用途

保证聚合间的数据一致性

替换批量处理

实现事件源模式

进行限界上下文集成

分类

内部事件:是一个领域模型内部的事件,不在限界上下文间进行共享

外部事件:是对外发布的事件,在多个限界上下文中进行共享

CollectRealtimeDispenseLogsEvent rdDe = new CollectRealtimeDispenseLogsEvent(spWork.getId() + "_update",0, operateInfo, "t_sup_work", spWork.getId(), 1);
DomainEventPublisherFactory.getRegisteredPublisher().publishEvent(rdDe);
public class CollectRealtimeDispenseLogsEvent implements DomainEvent {@ApiModelProperty(value="优先级 数字越大 越优先")private int priority=9;private DataChangeLogDTO log;private ExecutePoint executePoint = ExecutePoint.CURR_THREAD;public int getPriority() {return priority;}public DataChangeLogDTO getLog() {return log;}private String eventId;@Overridepublic String getEventId() {return eventId;}@Overridepublic Date obtainEventTime() {return null;}@Overridepublic AccessTokenUser getOperator() {return null;}@Overridepublic OperateInfo getOperateInfo() {return null;}@Overridepublic Object getEventData() {return null;}@Overridepublic ExecutePoint obtainExecutePoint() {return this.executePoint;}@Overridepublic String getEventType() {return this.getClass().getSimpleName();}public CollectRealtimeDispenseLogsEvent(String id, Integer priority, OperateInfo operateInfo, String u_table,String u_pk_vals, int u_type) {super();String logId=Utils.getUUID("");if(StringUtils.isBlank(id)) id=logId;this.eventId = this.getClass().getSimpleName()+"_"+id;if(priority!=null) this.priority = priority;long u_time=-1;String u_optor_id=null,u_optorg_id=null;if(operateInfo!=null) {u_time=operateInfo.obtainNotNullOperateTime().getTime();u_optor_id=operateInfo.obtainOperatorId();u_optorg_id=operateInfo.obtainOperateOrgId();}else{u_time=new Date().getTime();}this.log = new DataChangeLogDTO(logId, u_table, u_pk_vals, u_type, u_time,u_optor_id, u_optorg_id);}
}

贫血模型

指领域对象里只有get和set方法。

@Entity
@Table(name = "t_sup_work",indexes = {@Index(name = "idx_t_sup_work1", columnList = "sp_type")}
)
public class SuperviseWork extends ExBizEntity {@Column(length = 50)private String spType;@Column(length = 100)private String name;@AttributeOverrides({@AttributeOverride(name = "id", column = @Column(name = "p_sp_work_id", length = 100)),@AttributeOverride(name = "name", column = @Column(name = "p_sp_work_name", length = 100))})private SysDataSimpleValObj pSpWork;@OneToMany(mappedBy = "spWork", fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)@OrderBy("orderNo asc")private Set<SuperviseWorkCategoryParty> spCategoryParties = new LinkedHashSet<>();public SuperviseWork() {}public SuperviseWork(String spType, String name, SysDataSimpleValObj pSpWork) {this.spType = spType;this.name = name;this.pSpWork = pSpWork;}public String getSpType() {return spType;}public String getName() {return name;}public SysDataSimpleValObj getpSpWork() {return pSpWork;}public Set<SuperviseWorkCategoryParty> getSpCategoryParties() {return spCategoryParties;}
}

充血模型

大多业务逻辑和持久化放在Domain Object里面,Business Logic只是简单封装部分业务逻辑以及控制事务、权限等,这样层次结构就变成Client->(BusinessFacade)->Business Logic->Domain Object->Data Access Object

@Entity
@Table(name = "t_sup_rd_process",indexes = {@Index(name = "idx_t_sup_rd_process1", columnList = "party_id")}
)
public class SupRecordProcess extends ExBizEntity {@ManyToOne(optional = false)@JoinColumn(foreignKey = @ForeignKey(value = ConstraintMode.NO_CONSTRAINT))private SuperviseWork spWork;@ManyToOne(optional = false)@JoinColumn(foreignKey = @ForeignKey(value = ConstraintMode.NO_CONSTRAINT))private SuperviseRecord supRecord;@AttributeOverrides({@AttributeOverride(name = "id", column = @Column(name = "party_id", length = 100, nullable = false)),@AttributeOverride(name = "name", column = @Column(name = "party_name", length = 100, nullable = false))})private SysDataSimpleValObj party;@OneToMany(mappedBy = "partyPrc", fetch = FetchType.EAGER, cascade = CascadeType.REMOVE, orphanRemoval = true)@OrderBy("sendTime,createTime")private Set<SupRecordProcessSendRel> parents = new LinkedHashSet<>();//督办记录-承办  上级转办信息@OneToMany(mappedBy = "process", fetch = FetchType.EAGER, cascade = CascadeType.REMOVE, orphanRemoval = true)@OrderBy("orderNo")private Set<SupRecordProcessSendRel> sendRels = new LinkedHashSet<>();//督办记录-承办  转办下级信息private SysDataSimpleValObj acceptor;private boolean accepted;private Date acceptTime;private SysDataSimpleValObj operaeOrg;private SysDataSimpleValObj operateDept;private SysDataSimpleValObj operator;public SupRecordProcess() {}public SuperviseWork getSpWork() {return spWork;}public SuperviseRecord getSupRecord() {return supRecord;}public SysDataSimpleValObj getParty() {return party;}public Set<SupRecordProcessSendRel> getParents() {return parents;}public Set<SupRecordProcessSendRel> getSendRels() {return sendRels;}public SysDataSimpleValObj getAcceptor() {return acceptor;}public boolean isAccepted() {return accepted;}public Date getAcceptTime() {return acceptTime;}public SysDataSimpleValObj getOperaeOrg() {return operaeOrg;}public SysDataSimpleValObj getOperateDept() {return operateDept;}public SysDataSimpleValObj getOperator() {return operator;}//领域方法//签收public void doAccept(OperateInfo operateInfo) {this.accepted = true;this.acceptor = operateInfo.getOperator().getUser();this.acceptTime = new Date();this.appointOperator(operateInfo);if (CollectionUtils.isNotEmpty(this.parents)) {this.parents.stream().forEach(p -> p.doAccept(operateInfo));}}//指定当前经办人public void appointOperator(OperateInfo operateInfo) {if (this.accepted) throw new RuntimeException("当前办理记录已签收,请刷新页面");if (this.operator != null) {this.addAttr("beforeOperator", this.acceptor);if (this.operateDept != null) {this.addAttr("beforeOperateDept", this.operateDept);}if (this.operaeOrg != null) {this.addAttr("beforeOperaeOrg", this.operaeOrg);}}this.operaeOrg = operateInfo.getOperator().obtainOrg();this.operateDept = operateInfo.getOperator().obtainDept();this.operator = operateInfo.getOperator().getUser();}public void updateProcessInfo() {}
}
@Component
public class SuperviseRecordDomainService {//这里才是业务逻辑正在处理的地方法
}
@Service
@Transactional
public class SuperviseRecordServiceImpl implements ISuperviseRecordService {//这里只是将前端传递的参数进行转换调用SuperviseRecordDomainService中的方法
}

读写分离

CQRS

CQRS — Command Query Responsibility Segregation,故名思义是将 command 与 query 分离的一种模式。

CQRS 将系统中的操作分为两类,即「命令」(Command) 与「查询」(Query)。命令则是对会引起数据发生变化操作的总称,即我们常说的新增,更新,删除这些操作,都是命令。而查询则和字面意思一样,即不会对数据产生变化的操作,只是按照某些条件查找数据。

CQRS 的核心思想是将这两类不同的操作进行分离,然后在两个独立的「服务」中实现。这里的「服务」一般是指两个独立部署的应用。在某些特殊情况下,也可以部署在同一个应用内的不同接口上。

Command 与 Query 对应的数据源也应该是互相独立的,即更新操作在一个数据源,而查询操作在另一个数据源上。
对于项目而已,要看具体实际情况,是否需要按照上面这样操作,对于用于群体少的,比如只有几百人的项目根本不需要分成两个服务,只需要将命令和查询分成两个独立的类即可

@Service
@Transactional
public class SuperviseRecordServiceImpl implements ISuperviseRecordService {@Overridepublic SupProcessEditDTO saveNormalSuperviseRecord(Object ...) {//业务逻辑return null;}
}
@Service
@SuppressWarnings("unchecked")
public class NormalSupRecordQueryServiceImpl extends JpaBaseQueryServiceimplements INormalSupRecordQueryService {@Overridepublic PageResult<SupRecordWithPartyDTO> pageQueryNormalSupRecord(OperateInfo operateInfo, NormalSupRecordQueryVO vo,boolean withExport) {//查询逻辑return null;}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/443592.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

指针的深入了解6

1.回调函数 回调函数就是一个通过函数指针调用的函数。 如果你把函数的指针&#xff08;地址&#xff09;作为参数传递给另一个函数&#xff0c;当这个指针被用来调用其所指向的函数 时&#xff0c;被调用的函数就是回调函数。回调函数不是由该函数的实现方直接调用&#xff0…

vue实现瀑布流

每个色块宽度一致&#xff0c;高度自适应 <!DOCTYPE html> <html><head><meta charset"utf-8"><meta http-equiv"X-UA-Compatible" content"IEedge,chrome1"><meta name"renderer" content"we…

ModelArts加速识别,助力新零售电商业务功能的实现

前言 如果说为客户提供最好的商品是产品眼中零售的本质&#xff0c;那么用户的思维是什么呢&#xff1f; 在用户眼中&#xff0c;极致的服务体验与优质的商品同等重要。 企业想要满足上面两项服务&#xff0c;关键在于提升效率&#xff0c;也就是需要有更高效率的零售&#…

存内计算技术—解决冯·诺依曼瓶颈的AI算力引擎

文章目录 存内计算技术背景CSDN首个存内计算开发者社区硅基光电子技术存内计算提升AI算力知存科技存算一体芯片技术基于存内计算的语音芯片的实现挑战 参考文献 存内计算技术背景 存内计算技术是一种革新性的计算架构&#xff0c;旨在克服传统冯诺依曼架构的瓶颈&#xff0c;并…

TSINGSEE青犀智能分析网关V4—让加油站迈入AI智能检测时代

一、背景与需求 中国目前建设加油站超过10万个&#xff0c;作为高危场所对于烟火&#xff0c;危险区域管控、消防器材等管理要求严格&#xff0c;稍有不慎即酿成大祸。由于春节临近&#xff0c;加油站各类人员进出频繁&#xff0c;安全意识较低&#xff0c;依靠普通监控人力的…

探索半导体制造业中的健永科技RFID读写器的应用方案

一、引言 在当今高度自动化的工业环境中&#xff0c;无线射频识别&#xff08;RFID&#xff09;技术已经成为实现高效生产的重要一环。特别是在半导体制造业中&#xff0c;由于产品的高价值和复杂性&#xff0c;生产过程的追踪和管理显得尤为重要。健永科技RFID读写器以其出色…

编译Opencv3.3.1遇到的编译器无法识别的警告的问题解除:

问题描述&#xff1a; 本文&#xff0c;就是在一个硬件的SDK中用到了opencv3.3.1的版本&#xff0c;在笔者目前的VS2019,CUDA11版本下编译的问题和解决。在做Cmake的configure的时候&#xff0c;Cmake报了一个找不到编译器版本的错误, Selecting windows SDK version 10.0.1904…

day38 ● 509. 斐波那契数 ● 70. 爬楼梯 ● 746. 使用最小花费爬楼梯

动态规划是前一个状态推导过来的&#xff0c;贪心是局部最优解。 class Solution { public:int fib(int n) {int a0;int b1;int res0;if(n1) return 1;for(int i2;i<n;i){resab;ab;bres;}return res;} }; 可以由前面状态推出后面状态&#xff0c;是动态规划。由于始终只要后…

postman用法

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、postman怎么使用json输出 总结 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 提示&#xff1a;以下是本篇文章正文内容&#xff0…

VBA代码解决方案第十讲:利用VBA代码完成复制

《VBA代码解决方案》(版权10028096)这套教程是我最早推出的教程&#xff0c;目前已经是第三版修订了。这套教程定位于入门后的提高&#xff0c;在学习这套教程过程中&#xff0c;侧重点是要理解及掌握我的“积木编程”思想。要灵活运用教程中的实例像搭积木一样把自己喜欢的代码…

【Linux】600条最强Linux命令总结—— 干货满满!!!

目录 1. 基本命令 2. 关机 3. 文件和目录 4. 文件搜索 5. 挂载一个文件系统 6. 磁盘空间 7. 用户和群组 8. 文件的权限 使用 “” 设置权限&#xff0c;使用 “-” 用于取消 9. 文件的特殊属性 &#xff0c;使用 “” 设置权限&#xff0c;使用 “-” 用于取消 10. 打…

如何配置 Podman 使用国内镜像源?

Podman 配置国内镜像源 什么是 Podman&#xff1f;Docker 与 Podman 区别修改 Podman 容器注册表配置国内的镜像源Podman Container Registries 修改步骤检查配置是否生效 Podman 容器存储总结 什么是 Podman&#xff1f; Podman 是一种符合 OCI 标准的容器管理工具&#xff0c…