一、创建型 关注 如何创建对象 :把“怎么 new”与“怎么用”解耦,让系统不依赖具体类型。 1. 单例 Singleton 思想 :保证一个类只有一个实例,并提供全局访问点。逻辑:包内私有变量 + 受控获取入口 + 并发安全的一次性初始化。代价是隐含全局状态、不利测试,能用依赖注入时优先注入。 场景 :全局配置;日志器;数据库连接池( sql.DB 本身即单例使用)。 var once sync.Once var cfg *Config func GetConfig () * Config { once.Do( func () { cfg = loadConfig() }); return cfg } 2. 工厂方法 Factory Method 思想 :把“创建哪种对象”这个变化点封装起来,调用方只依赖接口,不直接 new 具体类型。逻辑:定义创建接口,由具体工厂决定产出,新增类型无需改调用方(开闭原则)。 场景 :按渠道创建通知器(短信/邮件/推送);按文件类型创建解析器;日志输出目标创建。 type Notifier interface { Send(msg string ) } type Creator interface { Create() Notifier } type SMSCreator struct {} func (SMSCreator) Create () Notifier { return &SMS{} } 3. 抽象工厂 Abstract Factory 思想 :一次创建“一整族”相关对象,保证它们互相兼容(不会把 S3 存储和阿里云队列混用)。逻辑:工厂接口含多个创建方法,切换工厂即整族切换。 场景 :多云适配(AWS/阿里云/GCP 的存储+队列成套创建);多数据库方言;UI 主题套件。 type CloudFactory interface { NewStorage() Storage; NewQueue() Queue } type AWSFactory struct {} func (AWSFactory) NewStorage () Storage { return &S3{} } func (AWSFactory) NewQ...
项目 内容 文档类型 技术设计文档 适用范围 购物车 / 结算页试算、订单创建、支付前复核、退款与结算 示例语言 Go 1.22(示例代码已通过单元测试与模糊测试) 1. 背景与目标 价格计算是电商交易链路中最容易产生资损的环节。一笔订单可能同时包含活动价、店铺券、平台券,用户只关心最终支付金额,但系统必须回答另外三个问题: 每一分优惠由谁出资 :商家、平台还是活动预算,这决定了结算。 每个订单行实际支付多少 :这决定了部分退款、开票和售后。 同样的输入是否永远得到同样的结果 :这决定了试算、下单、支付复核、对账能否互相印证。 本文给出一套以 价格漏斗 定义金额流向、以 责任链 组织计算节点、以 折后分摊 落实行级明细、以 一分钱兜底 守住金额下限的设计方案。 设计目标 编号 目标 说明 G1 可解释 任意一笔订单都能说清每层优惠减了多少、为什么 G2 可复算 给定输入与规则版本,结果唯一且确定 G3 可对账 明细求和等于总额,出资方可归集 G4 可扩展 新增优惠类型不修改既有节点 G5 防资损 任何组合都不会产生 0 元单或负数金额 非目标 :本文不涉及券的发放、营销预算投放与风控模型,只讨论下单环节的计价、分摊与核销一致性。 2. 术语与约定 术语 含义 订单行(Line) 订单中 SKU 维度的一条记录,分摊、退款的最小单位 商品级折扣 活动价、秒杀价、会员价等直接作用于商品单价的优惠 店铺券 商家出资,仅适用于该店铺商品 平台券 平台出资,可跨店铺适用 分摊基数 某张券作用时,各适用行的当前金额,用于按比例拆分券额 行级兜底 每个订单行实付不低于 MinPayPerLine (默认 1 个最小货币单位) 全局约定 金额一律使用 int64 ,单位为最小货币单位 (如“分”)。禁止 float64 ;不同币种的最小单位由币种配置决定,不得在代码中硬编码 100。 漏斗顺序固定 :商品级折扣 → 店铺券 → 平台券 → 兜底校验。顺序属于业务规则,需写入产品文档与规则版本,不得依赖调用顺序隐含。 门槛按作用时的金额判断 :店铺券判断商品折后金额...