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

时间:2012-01-08 17:49:42

标签: c# runtime overloading

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

我有一个班级:

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检查,必须有一种方法只进行一次检查并准备它。

在我的情况下,制作儿童班(比萨饼工人,汉堡工人等)不是一种选择,因为在我的实际案例中,班级很大,只有一个微小的差别。改变它将影响整个架构,因此需要避免。

7 个答案:

答案 0 :(得分:4)

创建一个抽象基类,其中包含工作人员可以执行的常见操作。然后为专业工作者声明派生类。

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 cascades和switch语句通常表示代码以过程而非面向对象的方式工作。重构它是面向对象的!

答案 1 :(得分:3)

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

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
    }
}

答案 2 :(得分:1)

这正是存在模式的原因:CommandStrategyDecorator

我相信你正在寻找的命令模式。首先,您有一个基本的“命令”模板:

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();
    }
}

如果您无法访问代码进行这些更改,那么您可能需要查看的其他模式是Adapter

答案 3 :(得分:1)

我仍然建议使用子类。如果无法从Worker继承,则创建在worker中使用的新类层次结构。这样任何使用Worker类的人都不必知道有子类。如果你真的很讨厌子类,或者你有其他原因你不想要它们,你可以使用字典。它包含作为键的作业类型和作为它调用的方法的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();
}

答案 4 :(得分:1)

不,我认为不应该避免。任何常见功能都应该放在基类中。我认为你需要一个静态factory method,它根据字符串参数返回一个子类。

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.

答案 5 :(得分:0)

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

制作

的基类
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,如果该类型不存在则抛出错误。

答案 6 :(得分:0)

必须更改其他类意味着您需要更改代码,而不是需要更改架构。最好的答案就是改变代码。从长远来看,必须以不太理想的方式编写它的维护负担将花费你不仅仅是改变代码。现在使用继承并咬紧牙关进行更改。如果你有迭代器会遇到处理子类型的问题,你的迭代器不仅仅是迭代器,而且你最好修复它而不是继续使用它们。如果其他类关心他们正在处理什么类型的工人,那么你应该修复这个问题。最终,依赖代码不应该关心它是哪种类型的工作者。无论如何,这真的是你的意思。作为基类型的类型的实例仍然是一个worker,这是使用worker的所有类都应该关心。