我正在构建一个自动应用程序,允许用户从复选框等中选择选项,并在最后显示费用。
问题是我完成这个应用程序的方式很尴尬。例如,请参阅我的if else语句,他们不会涵盖决策的各个方面。
例如,这是我的代码的一部分
private decimal RushesMethod(out decimal radiatorRush_var, out decimal transmissionFlush_var, out decimal both_var)
{
radiatorRush_var = 0m;
transmissionFlush_var = 0m;
both_var = 0m;
if (radiatorRushCheckBox.Checked)
{
radiatorRush_var = 30.00m;
}
else if (transmissionFlushCheckBox.Checked)
{
transmissionFlush_var = 80.00m;
}
else if (radiatorRushCheckBox.Checked && transmissionFlushCheckBox.Checked)
{
radiatorRush_var = 30.00m;
transmissionFlush_var = 80.00m;
both_var = radiatorRush_var + transmissionFlush_var;
}
return both_var + transmissionFlush_var + radiatorRush_var;
}
如果用户选择radiatorRushCheckBox.Checked
选项以及其他一些选项,而不是此方法,请说oilChangeCheckBox.Checked
,那么我将如何涵盖所有该决定。对于所有人来说,if else语句是一种过于冗长的方式,因为谁知道用户选择了什么。
如果我选择所有选项然后它没有显示正确的价格,会发生以下情况。
以下是完整的应用程序代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Automative_APP
{
public partial class automativeForm : Form
{
public automativeForm()
{
InitializeComponent();
}
private void ClearOilLube()
{
oilChangeCheckBox.CheckState = CheckState.Unchecked;
lubeJobCheckBox.CheckState = CheckState.Unchecked;
}
private void ClearFlushes()
{
radiatorRushCheckBox.CheckState = CheckState.Unchecked;
transmissionFlushCheckBox.CheckState = CheckState.Unchecked;
}
private void ClearMisc()
{
inspectionCheckBox.CheckState = CheckState.Unchecked;
replaceMufflerCheckBox.CheckState = CheckState.Unchecked;
tireRotationCheckBox.CheckState = CheckState.Unchecked;
}
private void ClearOthers()
{
partsTextBox.Text = "";
laborTextBox.Text = "";
}
private void ClearFees()
{
serviceLaborAnsLabelBox.Text = "";
partsSummaryAnsLabelBox.Text = "";
taxPartsAnsLabelBox.Text = "";
totalFeesAnsLabelBox.Text = "";
}
private decimal TotalCharges()
{
decimal rushesVar = RushesMethod();
decimal oiLAndLubeVar = OilLubeCharges();
decimal miscVar = MiscMethod();
decimal partsLaborVar = PartsLaborMethod();
decimal storeTaxCharges = TaxCharges();
decimal totalSum;
decimal totalSum1;
totalSum1 = (rushesVar + oiLAndLubeVar + miscVar);
totalSum = (rushesVar + oiLAndLubeVar + miscVar + partsLaborVar);
partsSummaryAnsLabelBox.Text = partsLaborVar.ToString();
partsSummaryAnsLabelBox.Text = partsTextBox.Text;
serviceLaborAnsLabelBox.Text = "Total Services fee is " + " " + totalFeesAnsLabelBox.Text + " " + "and Labor amount is" + " " + laborTextBox.Text;
taxPartsAnsLabelBox.Text = storeTaxCharges.ToString();
return totalSum;
}
private decimal TaxCharges()
{
const decimal PARTS_TAX_VAR = 0.6m;
decimal storeTax;
decimal taxCal;
storeTax = decimal.Parse(partsTextBox.Text);
taxCal = PARTS_TAX_VAR * storeTax;
return taxCal;
}
private decimal PartsLaborMethod()
{
decimal PL=0m;
decimal labor;
decimal totalPL = 0m;
PL = decimal.Parse(partsTextBox.Text);
labor = decimal.Parse(laborTextBox.Text);
totalPL= PL* labor;
return totalPL;
}
private decimal MiscMethod()
{
decimal valueTotal2 = 0m;
if (inspectionCheckBox.Checked && replaceMufflerCheckBox.Checked && tireRotationCheckBox.Checked)
{
valueTotal2 += (15.00m + 100.00m + 20.00m);
}
else if (inspectionCheckBox.Checked)
{
valueTotal2 += 15.00m;
}
else if (replaceMufflerCheckBox.Checked)
{
valueTotal2 += 100.00m;
}
else if (tireRotationCheckBox.Checked)
{
valueTotal2 += 20.00m;
}
return valueTotal2;
}
private decimal RushesMethod()
{
decimal valueTotal = 0m;
if (radiatorRushCheckBox.Checked)
{
valueTotal += 30.00m;
}
else if (transmissionFlushCheckBox.Checked)
{
valueTotal += 80.00m;
}
else if (radiatorRushCheckBox.Checked && transmissionFlushCheckBox.Checked)
{
valueTotal += (80.00m + 30.00m);
}
return valueTotal;
}
private decimal OilLubeCharges()
{
decimal valueTotalOL=0m;
if (oilChangeCheckBox.Checked && lubeJobCheckBox.Checked)
{
valueTotalOL += (26.00m + 18.00m);
}
else if (oilChangeCheckBox.Checked)
{
valueTotalOL += 26.00m;
}
else if (lubeJobCheckBox.Checked)
{
valueTotalOL += 18.00m;
}
return valueTotalOL;
}
private void partsSummaryLabelBox_Click(object sender, EventArgs e)
{
}
private void taxPartsLabelBox_Click(object sender, EventArgs e)
{
}
private void exitButton_Click(object sender, EventArgs e)
{
this.Close(); //close the form
}
private void calculateButton_Click(object sender, EventArgs e)
{
decimal totalStore= TotalCharges();
totalFeesAnsLabelBox.Text = totalStore.ToString();
}
private void clearButton_Click(object sender, EventArgs e)
{
ClearOilLube();
ClearFlushes();
ClearMisc();
ClearOthers();
ClearFees();
}
}
}
编辑:
这是问题所在,
The application should have the following value-returning methods:
• OilLubeCharges —Returns the total charges for an oil change and/or a lube job, if any.
• FlushCharges —Returns the total charges for a radiator flush and/or a transmission flush, if any.
• MiscCharges —Returns the total charges for an inspection, muffler replacement, and/or a tire rotation, if any.
• OtherCharges —Returns the total charges for other services (parts and labor), if any.
• TaxCharges —Returns the amount of sales tax, if any. Sales tax is 6% and is charged only on parts. If the customer purchases services only, no sales tax is charged.
• TotalCharges —Returns the total charges.
The application should have the following void methods, called when the user clicks the Clear button:
• ClearOilLube —Clears the check boxes for oil change and lube job.
• ClearFlushes —Clears the check boxes for radiator flush and transmission flush.
• ClearMisc —Clears the check boxes for inspection, muffler replacement, and tire rotation.
• ClearOther —Clears the text boxes for parts and labor.
• ClearFees —Clears the labels that display the labels in the section marked Summary
最后,我使用 @ OmegaMan 解决方案完成了这项工作。我想 发布更改,以便它可以帮助任何人
我对TotalCharges()方法进行了更改。比较前一个和这个。
private decimal TotalCharges()
{
decimal total = 0.0m;
if ( inspectionCheckBox.Checked)
total += 15.00m;
if (replaceMufflerCheckBox.Checked)
total += 100.00m;
if (tireRotationCheckBox.Checked)
total += 20.00m;
if (oilChangeCheckBox.Checked)
total += 26.00m;
if (lubeJobCheckBox.Checked)
total += 18.00m;
if (radiatorRushCheckBox.Checked)
total += 30.00m;
if (transmissionFlushCheckBox.Checked)
total += 80.00m;
return total;
我还更改了计算按钮CLICK EVENT HANDLER:
private void calculateButton_Click(object sender, EventArgs e)
{
decimal totalStore= TotalCharges();
decimal taxCharge = TaxCharges();
totalFeesAnsLabelBox.Text = (totalStore + taxCharge).ToString();
taxPartsAnsLabelBox.Text = taxCharge.ToString();
partsSummaryAnsLabelBox.Text = partsTextBox.Text;
serviceLaborAnsLabelBox.Text = "The Total Service charges are" + totalStore + "and Labor is " + laborTextBox.Text;
其余部分相同,逻辑成功。感谢所有贡献的人。
答案 0 :(得分:3)
要最小化此操作,您可以创建Checkbox到decimal(Price)的映射。当您需要计算与选中复选框相关的价格时,您只能使用一行。
首先,创建一个映射变量并在某个时候填充它(对我来说,我选择了表单加载 - 你可以在InitializeComponent();
之后在构造函数中完成它:
注意:将复选框重命名为有效复选框。
List<KeyValuePair<CheckBox, decimal>> checkboxPriceMapping;
private void Form1_Load(object sender, EventArgs e)
{
checkboxPriceMapping = new List<KeyValuePair<CheckBox, decimal>>
{
new KeyValuePair<CheckBox, decimal>(checkBox1, 26.0m),
new KeyValuePair<CheckBox, decimal>(checkBox2, 18.0m),
new KeyValuePair<CheckBox, decimal>(checkBox3, 15.0m),
new KeyValuePair<CheckBox, decimal>(checkBox4, 100.0m),
new KeyValuePair<CheckBox, decimal>(checkBox5, 20.0m),
new KeyValuePair<CheckBox, decimal>(checkBox6, 30.0m),
new KeyValuePair<CheckBox, decimal>(checkBox7, 80.0m),
};
}
然后,这是一种计算已检查控件总价的简单方法:
private decimal CalculateTotalPrice()
{
return checkboxPriceMapping.Where(x => x.Key.Checked).Sum(x => x.Value);
}
答案 1 :(得分:3)
在一个单独的方法中汇总和集中总计操作,并在完成总和时检查每个复选框的状态:
public decimal TotalCosts()
{
decimal total = 0.0m;
if ({Oil Changed Checked})
total += {Oil Cost};
if ({Transmission checked})
total += {Transmission total};
if ({Repair Clutch})
total += {Clutch Cost}; // Maybe call a separate method ClutchTotal()?
... { Do this for all check boxes }
return total;
}
不要尝试为不同的操作单独添加内容(就像使用both_var = radiatorRush_var + transmissionFlush_var;
那样,这就是你的困惑。
有限状态机
我提到了有限状态机逻辑,它可用于组织任何代码。
想想自动售货机,它必须采用所有不同类型的硬币和美元钞票,并且在它可以提供产品之前它具有某些状态。 通过映射所有状态然后集中代码来处理每个状态,这将使代码bug免费且可维护。
如果有人在机器上添加一角硬币,状态从Welcome
变为总计当前的硬币和美元但不提供产品。该状态为真,直到总数> 1。成本,然后命中Vend
状态,分配产品。在完成Welcome
的最后一步之前,它不会返回provide any monies if overpayment
状态。
通过设置状态,您可以组织一个代码来处理您在应用中看到的所有情况。
答案 2 :(得分:2)
我使用http://www.michael-whelan.net/rules-design-pattern/将此业务规则设计应用于您的问题,这就是我想出的。使用此方法,您可以将每个购买案例抽象为自己的&#34;规则&#34;如果您需要根据订单状态进行更复杂的操作,只需添加新规则或对现有规则进行更改即可。
我还建议您添加某种类型的数据库,以保存您的价格,税率以及您将来可能需要摸索的其他任何数字,如果您还没有保存任何历史数据。
public interface IExpenseRule
{
decimal CalculateExpense(Order customerOrder);
}
这代表我们订单的状态,并且是我们所有计算的真实来源。如果将来您需要更多属性以获得额外费用,那么可以从这里访问它们。例如,如果我想添加洗车,我可以在这里添加洗车标志,或者如果有洗涤水平则添加Enum。
public class Order
{
public bool HasOilChange { get; set; }
public bool HasLubeJob { get; set; }
public bool HasRadiatorRush { get; set; }
public bool HasTransmissionFlush { get; set; }
public bool HasInspection { get; set; }
public bool HasTireRotation { get; set; }
public bool HasMufflerReplacement { get; set; }
public decimal PartsCost { get; set; }
public decimal LaborsCost { get; set; }
}
以下是我们将规则应用于计算的地方。构造函数是将所有规则添加到规则集合的位置。 CalculateTotal迭代规则。规则只涉及它必须计算的任何项目。每个规则的结果都会加在一起以获得总数。 Sum
方法是Linq扩展,用于将规则的结果一起添加。如果你愿意,可以使用for循环。
public class OrderCalculator
{
List<IExpenseRule> rules = new List<IExpenseRule>();
//all your rules get added here
public OrderCalculator()
{
rules.Add(new OilChangeRule());
rules.Add(new LubeJobRule());
rules.Add(new TireRotationRule());
rules.Add(new TaxOnPartsRule());
}
//Runs all your calculations and returns the total based on the rules you feed and your order state
public decimal CalculateTotal(Order customerOrder)
{
var total = 0m;
total = rules.Sum(rule => rule.CalculateExpense(customerOrder));
return total;
}
}
有关规则的几个例子。如果我们有相互依赖的规则,我将其余部分作为OP的练习。
<pre><code>public class OilChangeRule : IExpenseRule
{
public const decimal OilChangeCost = 26.00m;
public decimal CalculateExpense(Order customerOrder)
{
return customerOrder.HasOilChange ? OilChangeCost : 0;
}
}
public class LubeJobRule : IExpenseRule
{
public const decimal LubeJobCost = 18.00m;
public decimal CalculateExpense(Order customerOrder)
{
return customerOrder.HasLubeJob ? LubeJobCost : 0;
}
}
public class TireRotationRule : IExpenseRule
{
public const decimal TireRotationCost = 20.00m;
public decimal CalculateExpense(Order customerOrder)
{
return customerOrder.HasTireRotation ? TireRotationCost : 0;
}
}
public class TaxOnPartsRule : IExpenseRule
{
public const decimal TaxPercentageOnParts = 0.6m;
public decimal CalculateExpense(Order customerOrder)
{
var taxOnParts = customerOrder.PartsCost * TaxPercentageOnParts;
return taxOnParts;
}
}</code></pre>
您的应用程序逻辑应该与任何UI分开。业务逻辑可以放入自己的dll中,并在之后的任何类型的应用程序中重用。 (是的,这段代码可能会进一步简化,但我认为这是相当简单明了的。)
public Order BuildOrder()
{
var currentOrder = new Order();
currentOrder.HasOilChange = oilChangeCheckBox.CheckState;
currentOrder.HasLubeJob = lubeJobCheckBox.CheckState;
currentOrder.HasRadiatorRush = radiatorRushCheckBox.CheckState;
currentOrder.HasTransmissionFlush = transmissionFlushCheckBox.CheckState;
currentOrder.HasInspection = inspectionCheckBox.CheckState;
currentOrder.HasMufflerReplacement = replaceMufflerCheckBox.CheckState;
currentOrder.HasTireRotation = tireRotationCheckBox.CheckState;
currentOrder.PartsCost = Decimal.Parse(partsTextBox.Text);
currentOrder.LaborsCost = Decimal.Parse(laborTextBox.Text);
return order;
}
private void calculateButton_Click(object sender, EventArgs e)
{
var totalCalculator = new OrderCalculator();
var partsCalculator = new PartsCalculator();
var serviceCalculator = new ServiceCalculator();
var order = BuildOrder();
var totalCost = totalCalculator.CalculateTotal(order);
var partsCost = partsCalculator.CalculateTotal(order);
var serviceCost = serviceCalculator.CalculateTotal(order);
//Do what you need to with the totals here;
totalFeesAnsLabelBox.Text = totalCost.ToString();
}