成本计算器应用程序的设计模式?

2024-03-27

我有一个问题,我之前曾尝试寻求帮助,但当时无法解决它,所以我现在尝试简化问题,看看是否可以获得更具体的帮助,因为它让我发疯了……

基本上,我有这个应用程序的工作(更复杂)版本,它是一个项目成本计算器。但因为我同时尝试学习更好地设计我的应用程序,所以我希望获得一些关于如何改进此设计的意见。基本上我想要的主要内容是输入(此处)在两个地方重复出现的条件。之前得到的建议是使用策略模式或者工厂模式。我还知道 Martin Fowler 的书,其中建议使用多态性进行条件重构。我在他更简单的例子中理解了这个原则。但是我该如何在这里做这些事情(如果合适的话)?在我看来,计算取决于几个条件: 1. 它是什么类型的服务,写作还是分析? 2. 项目是小型、中型还是大型? (请注意,可能还有其他参数,同样不同,例如“产品是新的还是以前存在的?”因此应该可以添加此类参数,但我试图使示例保持简单,仅使用两个参数能够得到具体的帮助)

因此,使用多态性进行重构意味着创建许多子类,我已经为第一个条件(服务类型)创建了多个子类,我真的应该为第二个条件(大小)创建更多子类吗?那会变成什么, AnalysisSmall、 AnalysisMedium、 AnalysisLarge、writingSmall 等等……???不,我知道这不好,我只是不知道如何使用该模式?

对于使用策略模式的建议,我基本上看到了同样的问题(我认为工厂模式只是实现上述多态性的帮助者)。因此,如果有人对如何以最佳方式设计这些类有具体建议,我将非常感激!还请考虑我是否也正确选择了对象,或者是否需要重新设计它们。 (像“你应该考虑工厂模式”这样的回应显然不会有帮助......我已经沿着这条路走下去了,我对在这种情况下到底是如何做到的感到困惑)

Regards,

Anders

代码(非常简单,不要介意我使用字符串而不是枚举,不使用数据配置文件等,一旦我掌握了这些设计问题,这将在实际应用程序中根据需要完成):

public abstract class Service
{
    protected Dictionary<string, int> _hours;
    protected const int SMALL = 2;
    protected const int MEDIUM = 8;

    public int NumberOfProducts { get; set; }
    public abstract int GetHours();
}

public class Writing : Service
{
    public Writing(int numberOfProducts)
    {
        NumberOfProducts = numberOfProducts;
        _hours = new Dictionary<string, int> { { "small", 125 }, { "medium", 100 }, { "large", 60 } };
    }

    public override int GetHours()
    {
        if (NumberOfProducts <= SMALL)
            return _hours["small"] * NumberOfProducts;
        if (NumberOfProducts <= MEDIUM)
            return (_hours["small"] * SMALL) + (_hours["medium"] * (NumberOfProducts - SMALL));
        return (_hours["small"] * SMALL) + (_hours["medium"] * (MEDIUM - SMALL))
            + (_hours["large"] * (NumberOfProducts - MEDIUM));
    }
}

public class Analysis : Service
{
    public Analysis(int numberOfProducts)
    {
        NumberOfProducts = numberOfProducts;
        _hours = new Dictionary<string, int> { { "small", 56 }, { "medium", 104 }, { "large", 200 } };
    }

    public override int GetHours()
    {
        if (NumberOfProducts <= SMALL)
            return _hours["small"];
        if (NumberOfProducts <= MEDIUM)
            return _hours["medium"];
        return _hours["large"];
    }
}

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 comboBoxNumberOfProducts_SelectedIndexChanged(object sender, EventArgs e)
    {
        Service writing = new Writing((int) comboBoxNumberOfProducts.SelectedItem);
        Service analysis = new Analysis((int) comboBoxNumberOfProducts.SelectedItem);

        labelWriterHours.Text = writing.GetHours().ToString();
        labelAnalysisHours.Text = analysis.GetHours().ToString();
    }
}

在您的计算中,服务类型、服务规模和产品数量之间存在紧密耦合,因此很难将它们分成模块化块以应用策略模式。

如果计算系统是固定的,那么策略模式似乎就不合适了。如果不是……那么,为什么不简化系统呢?

例如,从服务规模中提取基本小时数,并根据您的其他设置应用各种折扣或增加。

public class Service
{
    public IServiceSize serviceSize { internal get; set; }
    public IServiceBulkRate serviceBulkRate { internal get; set; }
    public IServiceType serviceType { internal get; set; }
    public int numberOfProducts { get; set; }

    /// <summary>
    /// Initializes a new instance of the <see cref="Service"/> class with default values
    /// </summary>
    public Service()
    {
        serviceSize = new SmallSize();
        serviceBulkRate = new FlatBulkRate();
        serviceType = new WritingService();
        numberOfProducts = 1;
    }

    public decimal CalculateHours()
    {
        decimal hours = serviceSize.GetBaseHours();
        hours = hours * serviceBulkRate.GetMultiplier(numberOfProducts);
        hours = hours * serviceType.GetMultiplier();

        return hours;
    }
}

public interface IServiceSize
{
    int GetBaseHours();
}

public class SmallSize : IServiceSize
{
    public int GetBaseHours()
    {
        return 125;
    }
}

public interface IServiceBulkRate
{
    decimal GetMultiplier(int numberOfProducts);
}

public class FlatBulkRate : IServiceBulkRate
{
    public decimal GetMultiplier(int numberOfProducts)
    {
        return numberOfProducts;
    }
}

public class StaggeredBulkRate : IServiceBulkRate
{
    public decimal GetMultiplier(int numberOfProducts)
    {
        if (numberOfProducts < 2)
            return numberOfProducts;
        else if (numberOfProducts >= 2 & numberOfProducts < 8)
            return numberOfProducts * 0.85m;
        else
            return numberOfProducts * 0.8m;
    }
}

public interface IServiceType
{
    decimal GetMultiplier();
}

public class WritingService : IServiceType
{
    public decimal GetMultiplier()
    {
        return 1.15m;
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

成本计算器应用程序的设计模式? 的相关文章

随机推荐

  • 警告:条件中的字符串文字

    使用下面的第一段代码我收到两条警告消息 warning string literal in condition x2 if input N n do this else input L l do this 而不是使用它 这不会导致任何警告
  • 如何在 VS2012 MVC4 项目中设置 Ext.NET 2.0?

    我非常怀疑我的问题是否会得到解答 但我会在这里尝试 因为我的挫败感如此之高 也许这会帮助我自己降低它们 所以 我想做的是 从头开始安装 VS2012 好吧 点击 exe 即可开始 创建一个新的MVC4项目 使用 Razor View Eng
  • 条件变量初始化的Pythonic方式是什么?

    由于 Python 的作用域规则 所有在某个作用域内初始化的变量此后都可用 由于条件不会引入新的作用域 因此不一定需要其他语言中的构造 例如在该条件之前初始化变量 例如 我们可能有 def foo optionalvar None some
  • AngularJS 文件拖放到指令中

    这个例子几乎完成了我想在 Angular js 中移植的功能 HTML5 文件 API http html5demos com file api view source 我一直在尝试用 google 搜索一些指令示例 但是我发现旧示例大量使
  • 选择具有特定属性的元素

    我的输入按钮没有任何类或 id 并且有 onclick attr 如下所示
  • SQL Server 闩锁及其对性能问题的指示

    我试图了解我们的数据库 SQL 2008 的潜在性能问题 特别是一个性能计数器 SQLServer Latches Total Latch Wait Time Total Latch Wait Time ms 我们看到数据库响应时间变慢 我
  • 隐藏打开的 Excel 文件

    这是我的问题 我开发了一个程序 它使用 Microsoft Excel COM 组件来读取 写入 Excel 文件 嗯 我的应用程序运行良好 但是当我在程序运行时直接使用 Excel 打开另一个文件时 我的应用程序使用的文件会出现在 Exc
  • 可以在同一台机器上安全地运行多个 Android 模拟器并使用套接字进行通信吗?

    我想在一台笔记本电脑 最坏情况 或专用网络上的多台计算机上模拟一小群 Android 设备 这是为了测试 Android 上的通信和进程迁移 有没有一种安全的方法可以从 Eclipse 下的给定应用程序识别并启动特定的模拟器 我最近安装了
  • 将 JSON 数据存储在 MySQL 表中

    我在使用 NodeJS 在 MySQL 表中存储 JSON 数据时遇到问题 JSON 数据如下所示 header file1 0 file2 1 subfiles subfile1 true subfile2 true response n
  • qVariantValue 是“QT_DEPRECATED” - 替代品是什么?

    我需要将 Qt 遗留代码从 4 转换为 5 1 现在我在 Visual Studio 2010 中出现编译错误 SingleItem item qVariantValue
  • 通过 Javascript WeakMaps 进行垃圾收集缓存

    我想在 JavaScript 中缓存大对象 这些对象是通过键检索的 缓存它们是有意义的 但它们不会一次全部放入内存中 因此我希望在需要时对它们进行垃圾收集 GC 显然更了解 使用以下命令创建这样的缓存非常简单WeakReference or
  • 安全跨线程信号/槽 C++

    似乎唯一为 Signal 类和槽中调用的内容提供安全跨线程信号的实现是 QT 也许我错了 但我不能在我正在做的项目中使用QT 那么我如何从不同的线程提供安全的 Slots 调用 例如使用 Boost signals2 插槽内的互斥体是唯一的
  • React Hooks with typescript:类型上不存在属性“数据”

    我有一个没有意义的错误 我正在用钩子输入我的状态值 但他说错误不是同一类型 已经尝试过使用空数组 甚至使用一些数据的数组 但错误总是相同的 import React useState from react import Row Col fr
  • 仅更新 DateTime 的日期部分

    我正在使用 SQL Server 2008 我在数据库中有一个日期时间 值为 10 4 2012 8 03 00 AM 如何仅更新日期部分 字段名称为 dTime 我想将日期更新为 10 5 2012 并保持时间不变 UPDATE tabl
  • 如果 bean 已经使用 @ConfigurationProperties 注解,@EnableConfigurationProperties 会有什么区别?

    Spring Boot 文档 https docs spring io spring boot docs 2 1 3 RELEASE reference html boot features external config html boo
  • 设置自定义 Maven 2 属性的默认值

    我有一个 Maven pom xml 其中包含一个我希望能够在命令行上控制的插件 一切工作正常 除了即使在网上搜索了一段时间后 我也不知道如何为我的控件属性设置默认值
  • 如何将 Cocoa 坐标从左上角 == 原点转换为左下角 == 原点

    我使用 CGWindowListCopyWindowInfo 来获取所有窗口的列表 它根据原点为我提供每个窗口的坐标top left屏幕的 如果我使用 NSWindow 的 setFrame 方法 则坐标基于原点左下方屏幕的 从一种方式转换
  • WPF 列表框滚动条不起作用

  • Backbone 可以逆序渲染集合吗?

    我正在使用 Signalr 中心来订阅服务器上的事件 事件被分派到集线器 它成功地将项目添加到 Marionette CollectionView 这又被呈现到表格中 因为事件表本质上是一个记事本 所以我希望事件按相反的顺序排列 并且最好只
  • 成本计算器应用程序的设计模式?

    我有一个问题 我之前曾尝试寻求帮助 但当时无法解决它 所以我现在尝试简化问题 看看是否可以获得更具体的帮助 因为它让我发疯了 基本上 我有这个应用程序的工作 更复杂 版本 它是一个项目成本计算器 但因为我同时尝试学习更好地设计我的应用程序