如何在运行时重载一个方法或C#中的其他想法

本文关键字:方法 其他 一个 运行时 重载 | 更新日期: 2023-09-27 18:19:48

也许重载一个方法并不完全是必要的,但这是我能想到的最好的方法。

我有一门课:

public class Worker {
    private string jobType;
    public Worker(string jt)
    {
        this.jobType = jt;
    }
    public void ProcessJob()
    {
         if(jobType.Equals("Pizza") MakePizza();
         else if (jobType.Equals("Burger") MakeBurger();
    }
    private void MakePizza()
    {
        // make pizza
    }
    private void MakeBurger()
    {
        // make burger
    }
}

以上只是一个示例。当构造类时,它是用特定的作业类型构造的,这不会改变。然而,它可能需要执行数百万个工作,而且总是相同类型的。ProcessJob()会一直被调用,但调用者不知道这是什么类型的工作程序。我想避免每次都运行if检查,必须有一种方法只进行一次检查并进行准备。

在我的情况下,开设儿童班(披萨工人、汉堡工人等)不是一种选择,因为在我的真实情况下,班级很大,只有一个微小的区别。更改它将影响整个体系结构,因此需要避免。

如何在运行时重载一个方法或C#中的其他想法

创建一个抽象基类,其中包含工人可以做的常见事情。然后为专门的工人声明派生类。

public abstract class Worker
{    
    public abstract void ProcessJob();
}
public class PizzaWorker : Worker
{
    public override void ProcessJob()
    {
        // Make pizza
    }
}
public class BurgerWorker : Worker
{
    public override void ProcessJob()
    {
        // Make burger
    }
}

现在你可以创建不同类型的工人,让他们完成自己的工作:

var workers = new List<Worker>();
workers.Add(new PizzaWorker());
workers.Add(new BurgerWorker());
foreach (Worker worker in workers) {
    woker.ProcessJob();
}

这将自动为每种类型的工作者调用正确的ProcessJob实现。


注意:If-else-If级联和switch语句通常表明代码以过程化而非面向对象的方式工作。将其重构为面向对象!

您可以使用在构建对象时创建的委托,这样调度就会自动完成:

public class Worker
{
    private delegate void MakeSomething();
    private MakeSomething makeWhat;
    private string jobType;
    public Worker(string jt)
    {
        this.jobType = jt;
        switch (jt)
        {
            case "Pizza":
                makeWhat = new MakeSomething(MakePizza);
                break;
            case "Burger":
                makeWhat = new MakeSomething(MakeBurger);
                break;
            default:
                throw new ArgumentException();
        }
    }
    public void ProcessJob()
    {
        makeWhat();
    }
    private void MakePizza()
    {
        //make pizza
    }
    private void MakeBurger()
    {
        //make burger
    }
}

我仍然建议使用子类。如果不能从Worker继承,则创建在Worker内部使用的新类层次结构。这样,任何使用Worker类的人都不必知道有子类。如果你真的很讨厌子类,或者你有其他原因不想要它们,你可以使用dictionary。它包含作业类型作为键,Action作为它调用的方法。如果您需要更多的作业,只需创建私有方法并在RegisterWorkers方法中注册即可。

private Dictionary<string, Action> actions = new Dictionary<string, Action>();
public Worker(string jt)
{
    this.jobType = jt;
    this.RegisterWorkers();
}
private void RegisterWorkers
{
    this.actions["Pizza"] = this.MakePizza;
    this.actions["Burger"] = this.MakeBurger;
}
public void ProcessJob()
{
    var action = this.actions[this.jobType];
    action();
}

不,我认为不应该避免。任何通用功能都应该放在基类中。我认为您需要一个静态工厂方法,它返回一个基于字符串参数的子类。

public abstract class Worker {
    public virtual void ProcessJob();
    public static Worker GetWorker(string jobType) {
        if(jobType.Equals("Pizza")
            return new PizzaWorker();
        else if (jobType.Equals("Burger")
            return new BurgerWorker();
        else
            throw new ArgumentException();
    }
    // Other common functionality
    protected int getFoo() {
        return 42;
    }
}
public class PizzaWorker : Worker {
    public override void ProcessJob() {
        // Make pizza
        int y = getFoo() / 2;
    }
}
public class BurgerWorker : Worker {
    public override void ProcessJob() {
        // Make burger
        int x = getFoo();
    }
}

所以使用这个:

Worker w = Worker.GetWorker("Pizza");
w.ProcessJob();   // A pizza is made.

这正是有模式的原因:Command、Strategy、Decorator。

我相信命令模式正是您所要寻找的。首先你有一个基本的"命令"模板:

public interface IJob {
    void ProcessJob();
}

然后将执行以下不同的作业:

public class MakePizza : IJob {
    // implement the interface
    public void ProcessJob() {
        // make a pizza
    }
}

现在,你可以有一个JobFactory如下:

public static class JobFactory {
    public static IJob GetJob(string jobType) {    
        if(jobType.Equals("Pizza"){
            return new MakePizza();
        } else (jobType.Equals("Burger") {
            return new MakeBurger();
        }
        // to add jobs, extend this if-else-if or convert to switch-case
    }
}

工人现在可以看起来像这样:

public class Worker {
    private IJob job;
    public Worker(string jt) {
        job = JobFactory.GetJob(jt);
    }
    public void ProcessJob() {
         job.ProcessJob();
    }
}

如果您无法访问代码来进行这些更改,那么您可能需要研究的另一种模式是适配器。

您在这里谈论的是基本继承。有几种方法可以做到这一点。

制作一个基类

public class Job
{
    virtual void ProcessJob();
}

然后是MakePizza

public class MakePizza : Job
{
    public void ProcessJob()
    {
       //make Pizza
    }
}

然后在工人类中,而不是将JobType作为string,这将导致各种潜在的错误。

public class Worker{

  private Job jobType;

  public Worker(Job jt){
    this.jobType = jt;
  }

  public void ProcessJob()
  {
    Job.ProcessJob();  
  }
}

如果你必须通过一个字符串,你可以简单地通过反射加载JobType,如果类型不存在,就会抛出一个错误。

必须更改其他类意味着您需要更改代码,而不是更改体系结构。最好的答案就是更改代码。从长远来看,必须以不太理想的方式编写这篇文章的维护负担将比仅仅更改代码花费更多。使用继承,现在就咬紧牙关做出改变。如果您的迭代器在处理子类型时会遇到问题,那么迭代器所做的不仅仅是迭代器,您最好解决这个问题,而不是继续使用它们。如果其他类关心他们正在处理的worker的子类型,那么这本身就是一个问题,您应该解决它。最终,依赖代码不应该关心它是哪种类型的工作者。无论如何,这才是你真正想要的。以工作为基类型的类型的实例仍然是一个工作者,这就是使用工作者的所有类应该关心的问题。