【问题标题】:c# Strategy Pattern per userc# 每个用户的策略模式
【发布时间】:2014-08-26 08:11:19
【问题描述】:

我有一个非常简单的场景。 我网站的用户可以是月会员或年会员

public class User
{
    public string UserName { get; set; }
    public MembershipType MembershipType { get; set; }
}

public enum MembershipType
{
    MONTHLY,
    ANNUALLY
}

然后根据会员资格,我采用不同的计费策略:

public interface IBillingStrategy
{
    void Bill(User user);
}

if (user.MembershipType == MembershipType.ANNUALLY)
{
     _billingStrategy = new AnnualBillingStrategy();
}
else if (user.MembershipType == MembershipType.MONTHLY)
{
      _billingStrategy = new MonthlyBillingStrategy();
}

这是非常直接和简单的。现在生意上来说“我想照顾我的朋友鲍勃,我希望你计算他的账单与其他人略有不同!”

所以如果我继续这个模式,我可以制作一个 BobBillingStrategy。然后我可以添加一些额外的逻辑,现在我有两种方法可以识别 Bob

if (user.UserName.Equals("bob"))
{
     _billingStrategy = new BobBillingStrategy();
}

这感觉很脏,因为我正在对用户名进行硬编码,只是我的运气 bob 创建了一个新用户。所以我可以向我的用户添加一个名为 IsBob 的布尔属性

if (user.IsBob)
{
     _billingStrategy = new BobBillingStrategy();
}

在我看来,两者都闻起来很有趣。我可以看到会发生什么,最终我将开始为 Fred 和 Ted 进行测试。我上面的代码可以工作,但我确信必须有一个更清洁的解决方案。

谢谢

【问题讨论】:

  • 是的,就像人们在这里回答的那样,您只需要在代码中实现那些“朋友策略”,但必须使用策略的确切用户应该可以在数据库级别进行配置。至少,这对我来说似乎是最不脏的解决方案。
  • 不建议使用枚举来存储成员类型。让会员成为动态的东西(见我的回答)
  • 顺便说一句,能不能换个角度看问题?例如,不是为 Bob 添加一个新的IBillingStrategy,而是添加新的业务对象,比如Discount,它可以被其他用户重用?这只是一个想法,我不知道你的确切问题。

标签: c# design-patterns strategy-pattern code-structure


【解决方案1】:

我会将 Membership 作为一个持有默认计费等的类。这将是一堆 if 的一吨清洁剂:

public class Membership
{

    public String Name { get; private set; }
    public BillingStrategy DefaultBillingStrategy {get; private set; }
    //Other properties

        public Membership(string name, BillingStrategy defaultBillingStrategy)
        {

            Name = name;
            DefaultBillingStrategy = defaultBillingStrategy;

        }

}

然后,你对你的用户做这样的事情:

public class User
{

    //same as before

    public BillingStrategy BillingStrategy {get; set; }

    public User(string Name, Membership membership, BillingStrategy billingStrategy = null)
    {

        name = Name;
        MemberShip = memberShip;
        BillingStrategy = billingStrategy ? membership.DefaultBillingStrategy;

    }

}
enter code here

还有;由于用户不想为 jan thorugh jun 支付费用,如果他们在 7 月加入,您可能希望保存一些有关用户会员资格何时到期的信息,并让会员资格在计费时/计费后设置此值

【讨论】:

  • 只是一个错字:User 不再是//same as before,因为你必须持有BillingStrategy。在我看来,您在Membership/ 方面不必要地使事情复杂化
  • by "//Same as before" 我指的是它原本拥有的属性(名称和成员资格)。我不明白你怎么能说我不必要地使会员资格复杂化。我宁愿说将不同类型的成员资格硬编码为一个枚举,然后使用一堆硬编码的 if 来检查该枚举以改变一些微不足道的事情,因为成员资格的持续时间会使事情变得更加复杂。
  • 对不起,我没有注意到BillingStrategy 属性,我完全错了。您将BillingStrategy 注入Membership,这意味着其他一些类必须控制该过程,或者您甚至需要一个新的类来实现该目的。 BillingStrategy 现在被注入到两个类中,需要更多的机制来支持它。我觉得这太复杂了。
  • 没问题。对不起,如果我看起来脾气暴躁。咖啡太多 + 睡眠不足 + 饿了 = 胡思乱想的程序员:P
  • 我在上面编辑了我的评论。是的,对大量 if 进行硬编码肯定比让 Membership 成为一个类更糟糕,我非常同意你的观点。
【解决方案2】:

对计费程序进行另一种变化:

public enum MembershipType
{
    MONTHLY,
    ANNUALLY,
    SPECIAL1
}

这样你至少可以将相同的过程分配给其他一些“朋友”

【讨论】:

  • 我对这个解决方案的问题是多年后,未来的编码员将有更多的WTF/分钟时刻,因为不清楚“special1”是什么。而且它仍然会丢失用户是每月或每年的事实(这可能会影响其他地方的代码逻辑)
【解决方案3】:

添加某种优惠券代码机制,这样如果您需要为其他用户进行不同的计算,那么它就足够灵活了。

【讨论】:

    【解决方案4】:

    您的 IBillingStrategy 究竟是做什么的?

    它是否负责实际向用户计费以及计算他们应该支付的费用?

    如果是这样,我会将这些职责分开,引入Invoice 的概念,然后允许在实际计费User 之前将用户特定的Discount 应用于生成的Invoice

    我可能会结合MembershipBillingStrategy 的概念(所以Membership 生成Invoices),使用BillingAction 来封装用户的计费方式(信用卡、邮寄发票、未标记公文包Bills) 引入Discounts 的概念(每个User 可以有多个Discounts)来处理新的需求并将整个事情封装在BillingService 中。

    当从您拥有的任何商店为用户补充水分时,我会给他们一个适当的Membership(反过来将使用一组Discounts 和其他信息进行初始化,例如会员日期等等)和一个适当的@ 987654336@.

    然后,作为计费流程的一部分(可能是每晚的事情),您将获得Users,将它们推送到BillingService,然后在其下方生成Invoices,并使用UsersBillingAction 对它们进行操作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-07
      • 1970-01-01
      • 1970-01-01
      • 2015-09-15
      • 1970-01-01
      相关资源
      最近更新 更多