围绕执行相同检查的多个 if 语句的代码重构 C# 问题

发布于 2024-11-17 17:00:50 字数 600 浏览 1 评论 0原文

我有一个方法,其中包含大量 if 语句,尽管我不确定如何改进代码,但看起来有点愚蠢。

这是一个例子。这个逻辑位于视图内部,现在位于控制器中,这要好得多,但我是否缺少一些东西,也许是一种设计模式阻止我检查 panelCount <; NumberOfPanelsToShow 并处理 panelCount 每个条件?也许不是,只是觉得丑!

非常感谢

if (model.Train && panelCount < NumberOfPanelsToShow)
{
    panelTypeList.Add(TheType.Train);
    panelCount++;
}
if (model.Car && panelCount < NumberOfPanelsToShow)
{
    panelTypeList.Add(TheType.Car);
    panelCount++;
}
if (model.Hotel && panelCount < NumberOfPanelsToShow)
{
    panelTypeList.Add(TheType.Hotel);
    panelCount++;
}
...

I have a method that has a load of if statements that seems a bit silly although I'm not sure how to improve the code.

Here's an example. This logic was inside the view which is now in the controller which is far better but is there something I'm missing, maybe a design pattern that stops me having to check against panelCount < NumberOfPanelsToShow and handling the panelCount every condition? Maybe not, just feels ugly!

Many thanks

if (model.Train && panelCount < NumberOfPanelsToShow)
{
    panelTypeList.Add(TheType.Train);
    panelCount++;
}
if (model.Car && panelCount < NumberOfPanelsToShow)
{
    panelTypeList.Add(TheType.Car);
    panelCount++;
}
if (model.Hotel && panelCount < NumberOfPanelsToShow)
{
    panelTypeList.Add(TheType.Hotel);
    panelCount++;
}
...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

半边脸i 2024-11-24 17:00:50

假设 Model.Train、Model.Car、Model.Plane 只是关于“模型”类型的布尔指示符(而不是您创建 Train : Model、Plane : Model 等)

public enum ModelType { Train, Car, Plane };

public class Model { 
    ... 
    public ModelType {get;set;}
    ... 
}

,并且在您的测试中:

if(panelCount < NumberOfPanelsToShow)
switch (Model.ModelType)
{
    case ModelType.Train :
        ...
        break;

    case ModelType.Plane :
...
}

但是,因为 Car、PLane 和火车是不同的,你真的应该有一个基本类型模型,从模型派生汽车,飞机和火车,然后你可以重载方法来处理每种类型

if (panelCount < NumberOfPanelsToShow)
{
    panelCount += AddModel(model);
}

private int AddModel(Plane model)
{ // do plane stuff here and on success return 1 else 0; }

private int AddModel(Train model)
{ // do train stuff here and on success return 1 else 0; }

private int AddModel(Car model)
{ // do car stuff here and on success return 1 else 0; }

Assuming Model.Train, Model.Car, Model.Plane are just boolean indicators as to the type of "model" (instead of you creating Train : Model, Plane : Model etc)

public enum ModelType { Train, Car, Plane };

public class Model { 
    ... 
    public ModelType {get;set;}
    ... 
}

and in your test:

if(panelCount < NumberOfPanelsToShow)
switch (Model.ModelType)
{
    case ModelType.Train :
        ...
        break;

    case ModelType.Plane :
...
}

HOWEVER, since Car, PLane and Train are different, you really SHOULD have a base type Model, derive Car, Plane and Train from Model and then you can overload methods to handle each type

if (panelCount < NumberOfPanelsToShow)
{
    panelCount += AddModel(model);
}

private int AddModel(Plane model)
{ // do plane stuff here and on success return 1 else 0; }

private int AddModel(Train model)
{ // do train stuff here and on success return 1 else 0; }

private int AddModel(Car model)
{ // do car stuff here and on success return 1 else 0; }
时光无声 2024-11-24 17:00:50

通常重构的方法是多态地进行,并负责决定对对象做什么,但由于您的决定是基于同一对象的不同方面,所以我不确定您可以在这里做到这一点。

我很想重构一个方法:

public AddIfSpace(bool thingToTest, TheType typeToAdd, ref currentCount)
{
    if (currentCount<NumberOfPanelsToShow && thingToTest)
    {
     panelTypeList.Add(typeToAdd);
     currentCount++;
    }
}

然后调用它:

AddIfSpace(model.Car,TheType.Car,ref panelCount);
AddIfSpace(model.Train,TheType.train,ref panelCount);
AddIfSpace(model.Hotel,TheType.Hotel,ref panelCount);

根据变量的范围,您可能需要更少或更多的参数,并且如果范围有限,您可以将其作为 panelTypeList 类型的扩展方法,这样您就结束了 这至少可以避免

panelTypeList.AddIfSpace(model.Car,TheType.Car,ref panelCount);
panelTypeList.AddIfSpace(model.Train,TheType.Train,ref panelCount);
panelTypeList.AddIfSpace(model.Hotel,TheType.Hotel,ref panelCount);

代码中的重复逻辑,并且意味着如果您想更改检查的工作方式,您可以在一个位置进行修改,并且如果您很好地命名该方法,应该传达意图并使代码更具可读性。

Usually the way to refactor this is to do it polymorphicly with the responsibility for deciding what to do being with the object, but as your decision is based on different aspects of the same object, I'm not sure you can do that here.

I would be tempted to refactor to a method instead:

public AddIfSpace(bool thingToTest, TheType typeToAdd, ref currentCount)
{
    if (currentCount<NumberOfPanelsToShow && thingToTest)
    {
     panelTypeList.Add(typeToAdd);
     currentCount++;
    }
}

then call it:

AddIfSpace(model.Car,TheType.Car,ref panelCount);
AddIfSpace(model.Train,TheType.train,ref panelCount);
AddIfSpace(model.Hotel,TheType.Hotel,ref panelCount);

you might need fewer or more params depending on scope of your variables, and you could make it an extension method on the type of panelTypeList if that has restricted scope so you end up with something like:

panelTypeList.AddIfSpace(model.Car,TheType.Car,ref panelCount);
panelTypeList.AddIfSpace(model.Train,TheType.Train,ref panelCount);
panelTypeList.AddIfSpace(model.Hotel,TheType.Hotel,ref panelCount);

This at least avoids the repeated logic in your code and means that you have a single place to modify if you want to change how the check works, and if you name the method nicely, should convey the intention and make the code more readable.

听风念你 2024-11-24 17:00:50

我将对此进行尝试,做出一些假设。

看起来您有某种“Panel”类,您正在尝试用数据模型对象(汽车、酒店、火车...)中的信息填充该类。相反,为什么不使用带有多态面板类(或 IPanel 接口)的 MVVM 类型模式),以及 CarPanel、HotelPanel、TrainPanel 等的子类...使用 ViewModel 对象,您的视图代码变得更加简单:

var newPanel = PanelFactory.GetPanel(data);  //Returns a CarPanel, HotelPanel, TrainPanel...
panelTypeList.Add(newPanel);
panelCount++;

I'm going to take a stab a this, making some assumptions.

It looks like you have some sort of "Panel" class which you're trying to fill up with information from data-model objects (Car, Hotel, Train...). Instead of that, why not use an MVVM type pattern with a polymorphic Panel class (or an IPanel interface), and subclasses of CarPanel, HotelPanel, TrainPanel, etc... With ViewModel objects, your view code gets even simpler:

var newPanel = PanelFactory.GetPanel(data);  //Returns a CarPanel, HotelPanel, TrainPanel...
panelTypeList.Add(newPanel);
panelCount++;
伊面 2024-11-24 17:00:50

现在没有 VS 来测试编译代码,但这应该传达逻辑。
您可以使用尽可能多的类型构建数组列表,而无需使用大量 if-else 或 switch 语句重复测试逻辑。

    TheType[] typesWithPanel = new TheType[] { TheType.Train, TheType.Car, TheType.Hotel};
    if (typesWithPanel.Contains(model.ModelType) && panelCount < NumberOfPanelsToShow)
    {
        panelTypeList.Add(model.ModelType);
        panelCount++;
    }

Dont have VS right now to test compiling the code, but this should convey the logic.
You can build up the array list with as many of the types without having to repeat the test logic with big if-else or switch statements.

    TheType[] typesWithPanel = new TheType[] { TheType.Train, TheType.Car, TheType.Hotel};
    if (typesWithPanel.Contains(model.ModelType) && panelCount < NumberOfPanelsToShow)
    {
        panelTypeList.Add(model.ModelType);
        panelCount++;
    }
倾其所爱 2024-11-24 17:00:50

我可能会做的是在模型上有一个枚举类型来切换。

if(panelCount < NumberOfPanelsToShow)
{
  switch(model.modelType)
  {
   case Model.Car:
    // do stuff
  break;
  }
  panelCount++;
}

不过,我们确实需要更多信息来确定如何处理这些案例以及在任何给定时间可以应用多少条件。

更新

鉴于您提供的附加信息,此处的其他一些答案似乎更合适。鉴于您当前的情况,这个答案是不够的。

What I'd probably do is have an enum type on the Model to switch against.

if(panelCount < NumberOfPanelsToShow)
{
  switch(model.modelType)
  {
   case Model.Car:
    // do stuff
  break;
  }
  panelCount++;
}

We'll need more information though really to determine how to handle the cases and how many conditions can apply at any given time.

UPDATE

Given the additional information you've provided, some of the other answers here seem more appropriate. This answer won't be sufficient given your current case.

天荒地未老 2024-11-24 17:00:50

不确定您如何称呼这种设计模式。但我曾经读过,每当您发现自己为不同类型执行重复的代码块(正如您正在做的那样)时,最好将该功能放入对象本身中。

您可以这样分解:

private const NumberOfPanelsToShow = 4;
private int panelCount = 0;

private void addToPanel(IPanelAddable element, PanelList panelTypeList) {
  if(panelCount < NumberofPanelsToShow) {
    element.addToPanelTypeList(panelTypeList);
    panelCount++;
  }
}

IPanelAddable 可以是定义 addToPanelTypeList 方法(或其他方法)的接口。然后在你原来的方法中:

if (model.Train)
{
    addToPanel(TheType.Train);
}
if (model.Car)
{
    addToPanel(TheType.Car);
}
if (model.Hotel)
{
    addToPanel(TheType.Hotel);
}

实际上你想避免上述情况,简化上面的 /wa 基类等......那么你的 TheType.* 对象显然需要实现“addToPanelTypeList”方法:

panelTypeList.Add(this);

你可以使用接口或继承为了达到同一个目标...

Not sure what you'd call this design pattern. But I read once that whenever you find yourself doing repetitive blocks of code for different types (as you're doing) that you are better off putting that functionality into the objects themselves.

You can break it out like this:

private const NumberOfPanelsToShow = 4;
private int panelCount = 0;

private void addToPanel(IPanelAddable element, PanelList panelTypeList) {
  if(panelCount < NumberofPanelsToShow) {
    element.addToPanelTypeList(panelTypeList);
    panelCount++;
  }
}

IPanelAddable can be an interface that defines the addToPanelTypeList method (or whatever). Then in your original method:

if (model.Train)
{
    addToPanel(TheType.Train);
}
if (model.Car)
{
    addToPanel(TheType.Car);
}
if (model.Hotel)
{
    addToPanel(TheType.Hotel);
}

Actually you want to avoid the above, simplify the above /w a base class, etc.... Then your TheType.* objects would obviously need to implement the "addToPanelTypeList" method:

panelTypeList.Add(this);

You can use interfaces or inheritance to achieve the same goal...

是伱的 2024-11-24 17:00:50

您可以随时查看规范模式。对于布尔逻辑来说非常方便:

public interface ISpecification<T>
{
    public bool IsSatisfiedBy(T candidate);
}

You could always take a look at the specification pattern. Quite handy for boolean logic:

public interface ISpecification<T>
{
    public bool IsSatisfiedBy(T candidate);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文