有条件的替换多态性与重构或类似的? [英] Replace conditional with polymorphism refactoring or similar?

查看:106
本文介绍了有条件的替换多态性与重构或类似的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我曾尝试之前问这个问题的一个变种。我得到了一些有用的答案,但依然没有什么感觉挺我的权利。在我看来,这不应该真的是一个难啃的骨头,但我没能找到一个优雅简单的解决方案。 (这是我以前的帖子,但请尝试看看这里表述为程序代码的第一个问题,以免被这似乎导致非常复杂的解决方案早先解释的影响:的 http://stackoverflow.com/questions/2772858/design-pattern-for-cost-calculator-app

I have tried to ask a variant of this question before. I got some helpful answers, but still nothing that felt quite right to me. It seems to me this shouldn't really be that hard a nut to crack, but I'm not able to find an elegant simple solution. (Here's my previous post, but please try to look at the problem stated here as procedural code first so as not to be influenced by the earlier explanation which seemed to lead to very complicated solutions: http://stackoverflow.com/questions/2772858/design-pattern-for-cost-calculator-app )

基本上,这个问题是创造所需的,可以包含大量的服务项目小时计算器。在这种情况下,书面和分析。小时计算不同,对于不同的服务:由每个产品小时率的产品的数量,和乘法写作计算产品被包含在项目,较低的小时率越多,但总数的时间逐步积累(即一个中等规模的项目,你都采取小范围的价格,然后添加中程定价至实际产品的数量)。而对于分析它的简单得多,它只是为每个尺寸范围内的散装率。

Basically, the problem is to create a calculator for hours needed for projects that can contain a number of services. In this case "writing" and "analysis". The hours are calculated differently for the different services: writing is calculated by multiplying a "per product" hour rate with the number of products, and the more products are included in the project, the lower the hour rate is, but the total number of hours is accumulated progressively (i.e. for a medium-sized project you take both the small range pricing and then add the medium range pricing up to the number of actual products). Whereas for analysis it's much simpler, it is just a bulk rate for each size range.

您将如何能够重构为一个优雅的,最好简单的面向对象的这版本(请注意,我永远不会写这样一个纯粹的程序的方式,这只是简洁地展现另一种方式的问题)。

How would you be able to refactor this into an elegant and preferably simple object-oriented version (please note that I would never write it like this in a purely procedural manner, this is just to show the problem in another way succinctly).

我一直在想在工厂,战略和装饰图案方面,但不能得到任何运行良好。 (我读Head First设计模式而回,都描述的装饰和工厂模式有一些相似之处这个问题,但我无法看到他们的好解决方案表示有该装饰例子似乎很复杂那里只需添加调味品,但也许它可以更好地工作,在这里,我不知道,至少事实的小时计算逐渐积累让我觉得Decorator模式......而从书与比萨工厂工厂模式的例子.. 。好它似乎只是创建类,至少在他们的榜样这样一个荒谬的爆炸。我以前找到很好的利用工厂模式,但我看不到我怎么会在这里使用它没有得到一个非常复杂的组类)

I have been thinking in terms of factory, strategy and decorator patterns, but can't get any to work well. (I read Head First Design Patterns a while back, and both the decorator and factory patterns described have some similarities to this problem, but I have trouble seeing them as good solutions as stated there. The decorator example seemed very complicated there for just adding condiments, but maybe it could work better here, I don't know. At least the fact that the calculation of hours accumulates progressively made me think of the decorator pattern... And the factory pattern example from the book with the pizza factory...well it just seems to create such a ridiculous explosion of classes, at least in their example. I have found good use for factory patterns before, but I can't see how I could use it here without getting a really complicated set of classes)

主要目标是只在一个地方(改变松耦合等),如果我要添加新的参数(比如其他尺寸,如XSMALL,和/或其他服务,如管理)。下面是程序的代码示例:

The main goal would be to only have to change in one place (loose coupling etc) if I were to add a new parameter (say another size, like XSMALL, and/or another service, like "Administration"). Here's the procedural code example:

public class Conditional
{
    private int _numberOfManuals;
    private string _serviceType;
    private const int SMALL = 2;
    private const int MEDIUM = 8;

    public int GetHours()
    {
        if (_numberOfManuals <= SMALL)
        {
            if (_serviceType == "writing")
                return 30 * _numberOfManuals;
            if (_serviceType == "analysis")
                return 10;
        }
        else if (_numberOfManuals <= MEDIUM)
        {
            if (_serviceType == "writing")
                return (SMALL * 30) + (20 * _numberOfManuals - SMALL);
            if (_serviceType == "analysis")
                return 20;
        }
        else //i.e. LARGE
        {
            if (_serviceType == "writing")
                return (SMALL * 30) + (20 * (MEDIUM - SMALL)) + (10 * _numberOfManuals - MEDIUM);
            if (_serviceType == "analysis")
                return 30;
        }
        return 0; //Just a default fallback for this contrived example
    }
}

有一个默认的备用

所有答复是赞赏! (不过,正如我在以前的帖子说我将不胜感激实际的代码示例,而不仅仅是试试这个模式,因为正如我所说,这是我遇到的麻烦是什么?)我希望有人有一个非常优雅的解决方案对这个问题,我其实从一开始以为会很简单...

All replies are appreciated! (But as I stated in my previous posts I would appreciate actual code examples rather than just "Try this pattern", because as I mentioned, that is what I'm having trouble with...) I hope someone has a really elegant solution to this problem that I actually thought from the beginning would be really simple...

================== ======================================

========================================================

新增加的:

我感谢所有的答案,到目前为止,但我仍然没有看到一个非常简单而灵活的解决问题的方法(一个我想止跌'T是非常复杂的在第一,但显然是)。这也可能是我还没有完全了解每个答案正确呢。不过,我想我会在(从阅读所有不同角度的答案在这里与一些帮助)的工作出来后我目前的尝试。请告诉我,如果我在正确的轨道与否。但至少现在的感觉就像它开始变得更加灵活。我可以很容易地添加新的参数,而无需在很多地方需要修改(我想!),和条件逻辑是在同一个地方。我在XML一些它来获得基础数据,从而简化了问题的一部分,它的一部分是一个战略型解决方案的一种尝试。

I appreciate all the answers so far, but I'm still not seeing a really simple and flexible solution to the problem (one I thought wouldn't be very complex at first, but apparently is). It may also be that I haven't quite understood each answer correctly yet. But I thought I'd post my current attempt at working it out (with some help from reading all the different angles in answers here). Please tell me if I'm on the right track or not. But at least now it feels like it's starting to get more flexible... I can quite easily add new parameters without having to change in lots of places (I think!), and the conditional logic is all in one place. I have some of it in xml to get the basic data, which simplifies part of the problem, and part of it is an attempt at a strategy type solution.

这里的代码:

 public class Service
{
    protected HourCalculatingStrategy _calculatingStrategy;
    public int NumberOfProducts { get; set; }
    public const int SMALL = 3;
    public const int MEDIUM = 9;
    public const int LARGE = 20;
    protected string _serviceType;
    protected Dictionary<string, decimal> _reuseLevels;

    protected Service(int numberOfProducts)
    {
        NumberOfProducts = numberOfProducts;
    }

    public virtual decimal GetHours()
    {
        decimal hours = _calculatingStrategy.GetHours(NumberOfProducts, _serviceType);
        return hours;
    }
}

public class WritingService : Service
{
    public WritingService(int numberOfProducts)
        : base(numberOfProducts)
    {
        _calculatingStrategy = new VariableCalculatingStrategy();
        _serviceType = "writing";
    }
}

class AnalysisService : Service
{
    public AnalysisService(int numberOfProducts)
        : base(numberOfProducts)
    {
        _calculatingStrategy = new FixedCalculatingStrategy();
        _serviceType = "analysis";
    }
}

public abstract class HourCalculatingStrategy
{
    public abstract int GetHours(int numberOfProducts, string serviceType);

    protected int GetHourRate(string serviceType, Size size)
    {
        XmlDocument doc = new XmlDocument();
        doc.Load("calculatorData.xml");
        string result = doc.SelectSingleNode(string.Format("//*[@type='{0}']/{1}", serviceType, size)).InnerText;
        return int.Parse(result);
    }
    protected Size GetSize(int index)
    {
        if (index < Service.SMALL)
            return Size.small;
        if (index < Service.MEDIUM)
            return Size.medium;
        if (index < Service.LARGE)
            return Size.large;
        return Size.xlarge;
    }
}

public class VariableCalculatingStrategy : HourCalculatingStrategy
{
    public override int GetHours(int numberOfProducts, string serviceType)
    {
        int hours = 0;
        for (int i = 0; i < numberOfProducts; i++)
        {
            hours += GetHourRate(serviceType, GetSize(i + 1));
        }
        return hours;
    }
}

public class FixedCalculatingStrategy : HourCalculatingStrategy
{
    public override int GetHours(int numberOfProducts, string serviceType)
    {
        return GetHourRate(serviceType, GetSize(numberOfProducts));
    }
}

和调用它一个简单的例子表(我猜我还可以有一个包含服务对象字典的包装工程类,但我还没有得到这一点):

And a simple example form that calls it (I guess I could also have a wrapper Project class with a Dictionary containing the Service objects, but I haven't gotten to that):

    public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        List<int> quantities = new List<int>();

        for (int i = 0; i < 100; i++)
        {
            quantities.Add(i);
        }
        comboBoxNumberOfProducts.DataSource = quantities;
    }


    private void CreateProject()
    {
        int numberOfProducts = (int)comboBoxNumberOfProducts.SelectedItem;
        Service writing = new WritingService(numberOfProducts);
        Service analysis = new AnalysisService(numberOfProducts);

        labelWriterHours.Text = writing.GetHours().ToString();
        labelAnalysisHours.Text = analysis.GetHours().ToString();
    }
    private void comboBoxNumberOfProducts_SelectedIndexChanged(object sender, EventArgs e)
    {
        CreateProject();
    }

}



(我是不是能包括XML,因为它得到了自动格式化这个网页上,但它基本上只是一堆,每个服务类型元素,并且含有小时速率值大小每个服务类型。)

(I wasn't able to include the xml because it got automatically formatted on this page, but it's basically just a bunch of elements with each service type, and each service type containing the sizes with the hour rates as values.)

我不知道如果我只是推了问题到XML文件(我仍然要添加新元素为每个新的服务类型,并在每个服务类型如果元素添加任何新的大小改变)。但也许这是不可能实现的正是我试图做的,不必做至少这种类型的变化。使用数据库,而不是XML的变化是添加一个字段和行作为简单的:

I'm not sure if I'm just pushing the problem over to the xml file (I'd still have to add new elements for each new servicetype, and add elements for any new size in each servicetype if that changed.) But maybe it's impossible to achieve what I am trying to do and not having to do at least that type of change. Using a database rather than xml the change would be as simple as adding a field and a row:

服务类型小中大

写作125 100 60

Writing 125 100 60

分析56 104 200

Analysis 56 104 200

(简单地格式化为表在这里,虽然列不太一致......我不是在数据库设计的最好,虽然,也许它应该做不同的,但你的想法...)

(Simply formatted as a "table" here, although the columns aren't quite aligned... I'm not the best at database design though, and maybe it should be done differently, but you get the idea...)

请告诉我你的想法!

推荐答案

我往往会开始枚举 ProjectSize {小,中,大} 和一个简单的函数返回给定numberOfManuals相应的枚举。从那里,我会写不同的 ServiceHourCalculators WritingServiceHourCalculator AnalysisServiceHourCalculator (因为他们的逻辑是十分不同)。每个将采取numberOfManuals,一个ProjectSize,并返回的小时数。我可能会创建一个从字符串ServiceHourCalculator地图,这样我就可以说:

I would tend to start with an enumeration ProjectSize {Small, Medium, Large} and a simple function to return the appropriate enum given a numberOfManuals. From there, I would write different ServiceHourCalculators, the WritingServiceHourCalculator and the AnalysisServiceHourCalculator (because their logic is sufficiently different). Each would take a numberOfManuals, a ProjectSize, and return the number of hours. I'd probably create a map from string to ServiceHourCalculator, so I could say:

ProjectSize projectSize = getProjectSize(_numberOfManuals);
int hours = serviceMap.getService(_serviceType).getHours(projectSize, _numberOfManuals);



这样,当我添加了一个新的项目规模,编译器会不惜一些未处理的情况下,每个服务。在一个地方这还不是全部处理,但它是所有处理之前会再次编译,而这就是我所需要的。

This way, when I added a new project size, the compiler would balk at some unhandled cases for each service. It's not all handled in one place, but it is all handled before it will compile again, and that's all I need.

更新
我知道的Java,而不是C#(非常好),所以这可能不是100%正确的,但创建地图会是这样的:

Update I know Java, not C# (very well), so this may not be 100% right, but creating the map would be something like this:

Map<String, ServiceHourCalculator> serviceMap = new HashMap<String, ServiceHourCalculator>();
serviceMap.put("writing", new WritingServiceHourCalculator());
serviceMap.put("analysis", new AnalysisServiceHourCalculator());

这篇关于有条件的替换多态性与重构或类似的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆