簡體   English   中英

如何在運行時重載方法或C#中的其他想法

[英]How to overload a method at run-time or other ideas in C#

也許重載方法並不完全是必需的,但這是我能想到的最好的方法。

我有一堂課:

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檢查,必須有一種方法只能執行一次檢查並進行准備。

在我的情況下,讓孩子上課(披薩工人,漢堡工人等)不是一種選擇,因為在我的實際情況下,班級很大,只有一個微小的區別。 更改它會影響整個體系結構,因此需要避免。

創建一個抽象基類,其中包含工作人員可以執行的常見操作。 然后為專業工作者聲明派生類。

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

這就是為什么有模式的原因: 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

我仍然建議使用子類。 如果您不能從Worker繼承,則創建在worker內部使用的新類層次結構。 這樣,使用Worker類的任何人都不必知道存在子類。 如果您真的很討厭子類,或者您有其他原因不希望使用它們,則可以使用字典。 它包含作業類型作為鍵,並包含操作作為其調用的方法。 如果您需要更多工作,只需創建私有方法並在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.

您在這里談論的是基本繼承。 您可以通過兩種方法來執行此操作。

使一個基類是

public class Job
{
    virtual void ProcessJob();
}

然后是MakePizza

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

然后在您的worker類中,而不是將JobType作為string ,這將導致各種潛在的錯誤。

public class Worker{


  private Job jobType;


  public Worker(Job jt){

    this.jobType = jt;
  }


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

}

如果必須通過字符串,則可以通過反射簡單地加載JobType,如果類型不存在,則拋出錯誤。

必須更改其他類意味着您需要更改代碼,而不是需要更改體系結構。 最好的答案就是更改代碼。 從長遠來看,不得不以不理想的方式編寫代碼的維護負擔將使您付出的代價不僅僅是更改代碼。 使用繼承並立即做出更改。 如果您的迭代器在處理子類型時會遇到問題,那么您的迭代器所要做的不只是作為迭代器,而且與解決這些問題相比,最好將其修復。 如果其他類關心他們正在處理的工作者的子類型,那么這本身就是一個問題,您應該解決。 最終,從屬代碼不應關心它是哪種類型的工作程序。 無論如何,那確實是你想要的。 具有工作作為其基本類型的類型的實例仍然是worker,而使用該worker的所有類都應該關心它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM