【问题标题】:Template method - enforce method to call another method模板方法 - 强制方法调用另一个方法
【发布时间】:2016-11-16 07:52:16
【问题描述】:

假设我们有以下类:

public class Employee
{
  public string Name { get; private set; } 
  public string Team { get; private set; }

  public Employee(string name, string team)
  {
    this.Name = name;
    this.Team = team;
  }

  public void UpdateName(string newName, string updatedBy)
  {
    this.Name = newName;

    this.Update(updatedBy);
  }

  public void UpdateTeam(string newTeam, string updatedBy)
  {
    this.Team = newTeam;

    this.Update(updatedBy);
  }

  private void Update(string updatedBy)
  {
    // and do something with updatedBy
  }
}

在 C# 中是否有更好的方法可以强制执行方法(例如 UpdateTeam 调用 Update 方法并将字符串参数传递给它 - 例如 updatedBy)?

当然没有这样的语法,只是为了说明我的意思:

public class Employee
{
  // ...

  public void UpdateTeam(string newTeam, string updatedBy) : Update(updatedBy)
  {
    this.Team = newTeam;
  }

  private void Update(string updatedBy)
  {
    // and do something with updatedBy
  }
}

编辑:我知道“模板”模式,这不是我需要的。

【问题讨论】:

  • 非声明式 - 您可以通过单元测试验证您是否获得了正确的结果,但没有强制执行特定实现的机制。
  • 您可以使用 Postsharp 之类的工具查看 Aspect-oriented programming

标签: c# oop


【解决方案1】:

将代码添加到NameTeam 的设置器中,它将设置一个内部属性,然后调用Update

UpdatedBy 应该在另一个类中。您现在将 2 个职责混合到一个类中。

【讨论】:

  • @DStanley 添加了不应进入此类的注释
【解决方案2】:

不,没有比您已经建议的更好的方法了。 :)

当然还有其他一些方法可以做到这一点(设置属性而不是调用方法,甚至可能调用事件,但在所有情况下都需要手动添加该调用。)

您可能需要考虑 AOP。 AOP 允许您定义一个特殊属性,该属性可以在调用公共方法之前或之后调用方法。当然,您仍然需要手动添加该属性。

更多关于AOP的信息,请看:https://www.postsharp.net/

【讨论】:

  • 感谢您的回复,手动添加属性不是问题。
【解决方案3】:

我认为模型应该是轻量级的,并且模型类中没有业务逻辑的位置。您应该考虑在单独的类中提取业务逻辑。这个概念可能会有所帮助:

public class UpdateNameCommand : ICommand<UpdateNameContext>
{
    public void Execute(UpdateNameContext context)
    {
        UpdateEmployeeName(context.NewName);
        UpdateTeam(context.UpdatedBy);
    }

    private void UpdateEmployeeName(string name)
    {
        // ...
    }

    private void UpdateTeam(string updatedBy)
    {
        // ...
    }
}

public interface ICommand<TContext>
{
    void Execute(TContext context);
}

其中命令上下文是一个简单的类,负责将数据传递给命令并(如果需要)在命令执行后接收结果。

它不一定应该是一个命令,而是任何负责业务案例的单独类。其他程序员应该使用它来执行这个特定的动作。这个类(或方法)应该封装必要的逻辑并暴露简单的接口以便从外部调用。

关于SOLID principles 的好读物。所描述的方法至少包含 2 个原则,可能更多,具体取决于您的应用程序需求:

S - 单一责任
O - 开闭原则

【讨论】:

  • 感谢您的回复。但是我觉得与该对象相关的业务逻辑完全属于该对象,就像我的示例一样。这不就是面向对象编程的核心原则吗?我不认为我违反了“S”,因为公开的方法仍然承担着同样的责任——维护 Employee 对象。如果我要将这个逻辑提取到命令/处理程序模式中,我们实际上是从 OOP(富模型)转向过程编程(贫血模型)。
  • @HristoYankov 这是你的意见,我尊重它。我只是相信模型应该是轻量级的。我也更喜欢将业务逻辑与模型分开。我认为在现实世界的应用程序中会有很多与模型相关的业务逻辑,如果你把它们都放在一个类中,single responsibility 就太多了。即使现在您拥有实际上属于 Team 类而不是 Employee 的 UpdateTeam 方法。非常有争议,这只是我的意见。
  • 对不起,我把它命名错了。它与管理另一个对象(即团队)无关。应该称它为“年龄”之类的。无论如何,我喜欢你的指挥方式。
  • @HristoYankov 谢谢。我并不是在批评你的方法。每个人都有偏好。希望您能找到解决问题的好方法。 Martin 建议使用 AOP,它可能对你有所帮助。
【解决方案4】:

也许您可以尝试使用面向方面的编程。看起来AOP可以帮助你。定义之一是:

方面是一种常见的特征,通常分散在 方法、类、对象层次结构,甚至整个对象模型。它 是看起来和闻起来应该有结构的行为,但是 你找不到用代码表达这种结构的方法 传统的面向对象技术。

因此,您需要通过更改名称或团队来完成额外的工作。由于您的设计简洁,因此不应将“额外工作”与您的代码混在一起。

这里有一篇非常好的帖子: What is aspect-oriented programming?

【讨论】:

    猜你喜欢
    • 2014-07-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-24
    相关资源
    最近更新 更多