V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
unregister
V2EX  ›  程序员

一个设计模式相关的问题,怎么计算账单的费用?符合开闭原则

  •  
  •   unregister · 305 天前 · 1426 次点击
    这是一个创建于 305 天前的主题,其中的信息可能已经有所发展或是发生改变。

    如果现在有一个账单的规则,有多种不同的计费方式( Billing A ,B ,C ,D ,E ),然后每一种计费方式还有一些主要的区别,每种计费方式还对应不同的计费周期,比如两种计费周期(计费月和自然月)计费月账单周期是比如说 2 月 14-3 月 13 ,3 月 14-4 月 13 ,自然月则比如是 2 月 1 号-2 月 28 号,3 月 1 号-3 月 31 。如果使用策略模式的话 A ,B ,C ,D ,E 五种策略,但里面都还要判断一下计费月还是自然月类型的,感觉这个比较累赘。就好比我一辆混动车子都能开,但是里面有时候烧油,有时候烧电。有没有比五种策略模式里用 if else 判断计费周期更好的方式?后面还要考虑到滞纳金的计算

    14 条回复    2023-05-30 14:57:24 +08:00
    leopod1995
        1
    leopod1995  
       305 天前
    统一的消费记录 然后根据不同的计费模式开不同的表 每种表对应相应的计费模式 后续也好拓展 数据从消费记录拿 定时去写统计表 或者消费记录表去触发

    坏处是数据冗余太多,好处是逻辑性能好
    iffi
        2
    iffi  
       305 天前   ❤️ 1
    感觉这种多维度变化的时候用 桥接模式,要不你试试
    iyiluo
        3
    iyiluo  
       305 天前   ❤️ 1
    责任链,只处理符合条件的账单
    thinkershare
        4
    thinkershare  
       305 天前   ❤️ 1
    为每个算子策略提供 factory, 每个策略有自己独立的 Factory.
    fiypig
        5
    fiypig  
       305 天前   ❤️ 1
    房租季度收租, 电费月度收租,这个意思吗
    7911364440
        6
    7911364440  
       305 天前   ❤️ 1
    桥接模式,计费方式接口给每个计费周期单独定义方法。
    再给计费周期定义成桥接类,每个类型的桥接类调用不同的计费方式接口的方法。
    NGXDLK
        7
    NGXDLK  
       305 天前   ❤️ 1
    策略模式可以实现,但如果套娃的话确实有点累赘;
    桥接的话,看起来好像会简洁一点,可以尝试一下。

    扔个链接:桥接模式 https://www.runoob.com/design-pattern/bridge-pattern.html
    unregister
        8
    unregister  
    OP
       305 天前
    @iffi 是的,桥接模式适合多个维度的
    @7911364440 是的,厉害了
    @NGXDLK 确实是桥接模式适合解决这种情况。
    unregister
        9
    unregister  
    OP
       305 天前
    unregister
        11
    unregister  
    OP
       304 天前
    @zhoupeng199 是的,看了职责链模式,感觉确实很合适。👍账单规则,计费周期,还有滞纳金,比如还有计费的精度都可以用 Handler 去处理
    zzyphp111
        12
    zzyphp111  
       304 天前
    桥接模式比较合适,下面是一个例子

    ```go
    // 实现部分
    type DrawAPI interface {
    drawCircle(radius int, x int, y int)
    }
    type RedCircle struct{}
    func (r *RedCircle) drawCircle(radius int, x int, y int) {
    fmt.Printf("Drawing Circle[ color: red, radius: %d, x: %d, y: %d]\n", radius, x, y)
    }
    type GreenCircle struct{}
    func (g *GreenCircle) drawCircle(radius int, x int, y int) {
    fmt.Printf("Drawing Circle[ color: green, radius: %d, x: %d, y: %d]\n", radius, x, y)
    }

    // 抽象部分
    type Shape interface {
    draw()
    }
    type Circle struct {
    x int
    y int
    radius int
    drawAPI DrawAPI
    }
    func (c *Circle) draw() {
    c.drawAPI.drawCircle(c.radius, c.x, c.y)
    }

    // 使用桥接连接抽象和实现
    func main() {
    redCircle := &Circle{1, 2, 3, &RedCircle{}}
    greenCircle := &Circle{4, 5, 6, &GreenCircle{}}
    redCircle.draw()
    greenCircle.draw()
    }
    ```
    japeth
        13
    japeth  
       304 天前
    责任链模式
    unregister
        14
    unregister  
    OP
       304 天前
    @zzyphp111 职责链模式感觉更合适,因为还需要满足其他条件,比如滞纳金,计费精度啥的,可以依次使用各不同的 handler 处理
    @japeth 是的🤙
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2873 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 13:02 · PVG 21:02 · LAX 06:02 · JFK 09:02
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.