Java 如何改进这段代码?
当前订单处理器的实现已关闭以进行扩展,并打开以进行修改以添加新的折扣代码,如何改进设计以消除此限制在该Java 如何改进这段代码?,java,design-patterns,Java,Design Patterns,当前订单处理器的实现已关闭以进行扩展,并打开以进行修改以添加新的折扣代码,如何改进设计以消除此限制在该calculateTotalPriceWithDiscountCode函数中,将折扣代码作为参数传递不是一个好主意。嗯,第三个人,谁审查你的代码,不会明白,不会明白它意味着什么,除了你,一种代码气味 其中一个建议是,您需要创建另一个名为Discount的类,并将Discount对象作为参数传递,然后从其公共方法中获取内部值 i、 e 现在,您真正需要修改的将是折扣类,您的CalculateTot
calculateTotalPriceWithDiscountCode
函数中,将折扣代码作为参数传递不是一个好主意。嗯,第三个人,谁审查你的代码,不会明白,不会明白它意味着什么,除了你,一种代码气味
其中一个建议是,您需要创建另一个名为Discount的类,并将Discount对象作为参数传递,然后从其公共方法中获取内部值
i、 e
现在,您真正需要修改的将是
折扣
类,您的CalculateTotalPrice WithDiscountCode
将不需要关心。我的想法是单独维护折扣
public class Discount {
//Use a hash map to store your Code associate with your discountAmount
public Discount(char discountCode){
this.discountCode = discountCode
}
public int getDiscountAmount(){
....
....
}
}
////////////////
public class OrderProcessor {
public Double calculateTotalPriceWithDiscountCode(Order order,
char discountCode) {
Double itemTotal = order.getItemTotal();
return itemTotal - (itemTotal* Discounts.GetDiscounts(discountCode));
}
}
一般来说,
开关
的存在是一个相当好的赠品,可以用来说明类应该是什么。所以,第一次尝试是这样的:
class Discounts
{
public static double GetDiscounts(char discountCode)
{
switch (discountCode) {
case 'A':
return 0.95d;
case 'B':
return 0.15d;
default:
return 0.00d;
}
}
}
public interface Discounter {
public double applyDiscount(double itemTotal);
}
public class OrderProcessor {
private Map<Char, Discounter> discounts = new HashMap<Char, Discounter>();
public void addDiscounter(Char discountCode, Discounter discounter) {
discounts.put(discountCode, discounter);
}
public Double calculateTotalPriceWithDiscountCode(Order order, char discountCode) {
double itemTotal = order.getItemTotal();
double discountAmount = 0.0;
if (discounts.hasKey(discountCode))
discountAmount = discounter.applyDiscount(itemTotal);
return itemTotal - discountAmount;
}
}
你也可以做一个删除方法,然后你的折扣店会变得更复杂,查阅外部数据等等。你可能想打开一点界面,并通过整个订单进行更多检查
注意:如果这是您在生产中要做的事情,我有两条未经请求的建议:
double
。)正如您指出的,折扣代码需要更改,最好将实际折扣代码与代码分开。在
xml
或设置文件中维护折扣代码,并在使用之前将值惰性加载到字典/哈希集中
例如,您的xml可能如下所示
processor.addDiscounter('A', new Discounter() {
public double applyDiscount(double itemTotal) {
return 0.95 * itemTotal;
}
});
如果您的折扣xml
可能在程序执行期间发生变化,则在需要折扣值时执行Load
操作(与在上述代码片段中加载一次相比)
然后访问代码(键)以检索折扣(值)
将基于订单计算总计的逻辑拉入其自己的类/接口:
if(discountsDictionary.ContainsKey(discountCode))
{
discount = discountsDictionary[discountCode];
discountedItemPrice = itemPrice * ( 1 - discount);
}
else
{
// Invalid discount code...
}
类OrderProcessor{
//可能会将其注入或以静态工厂以外的其他方式加载
私有集合计算器=TotalCalculatorFactory.getTotalCalculators();
带有折扣代码(订单、字符折扣代码)的公共双重计算总价{
for(TotalCalculator:计算器){
if(计算器支持(折扣代码)){
返回计算器。计算器总计(订单);
}
}
returnorder.getItemTotal();
}
}
类总数计算器{
私有字符折扣码;
私人双重折扣;
公共总计计算器(字符折扣代码、双折扣代码){
this.discountCode=折扣代码;
this.discountRatio=discountRatio;
}
公共布尔支持(字符折扣代码){
返回此值。折扣代码==折扣代码;
}
公共双计算总计(订单){
退货订单.getItemTotal()-订单.getItemTotal()*折扣;
}
}
类TotalCalculatorFactory{
公共静态集合getTotalCalculators(){
返回数组.asList(
新的TotalCalculator('A',0.95),
新的TotalCalculator('B',0.15)
);
}
}
在实际系统中,我会将TotalCalculator作为一个接口,它还有一个额外的优势,即能够以其他方式计算订单总额,而不仅仅是降低百分比折扣
此解决方案还非常灵活,允许您使用其他机制创建TotalCalculator(或接口实现),而不是手动将其编码到工厂中。例如,您可以使用IoC容器来创建和注入代码,或者使用查找和加载代码。您可以使用单独的xml文件来存储代码及其计算机制 这将消除不能添加新折扣代码的限制 XML文件:折扣.XML
class OrderProcessor {
// Probably inject this or load it some other way than a static factory
private Collection<TotalCalculator> calculators = TotalCalculatorFactory.getTotalCalculators();
public Double calculateTotalPriceWithDiscountCode(Order order, char discountCode) {
for (TotalCalculator calculator : calculators) {
if (calculator.supports(discountCode)) {
return calculator.calculateTotal(order);
}
}
return order.getItemTotal();
}
}
class TotalCalculator {
private char discountCode;
private double discountRatio;
public TotalCalculator(char discountCode, double discountRatio) {
this.discountCode = discountCode;
this.discountRatio = discountRatio;
}
public boolean supports(char discountCode) {
return this.discountCode == discountCode;
}
public Double calculateTotal(Order order) {
return order.getItemTotal() - order.getItemTotal() * discountRatio;
}
}
class TotalCalculatorFactory {
public static Collection<TotalCalculator> getTotalCalculators() {
return Arrays.asList(
new TotalCalculator('A', 0.95),
new TotalCalculator('B', 0.15)
);
}
}
注意:操作代码(我打算如何处理这些值?)当前未实现。您可以在您的终端实现相同的功能
使用XML解析器类:
Class:DiscountModel.java(该类是存储折扣代码的模型)
Class:DiscountParser.java(这将解析discounts.xml文件并将代码存储在列表中)
无论何时添加新代码,都可以将其插入到xml文件中。如果需要删除折扣代码,同样适用
希望以上内容能有所帮助。无论如何,你为什么要使用
discountCode
?为什么不将该金额作为浮点数传递?您的限制是什么?只需在记事本中键入它。抱歉,此组件上没有sdk。您只将代码和问题转移到了另一个类。基于“开放供修改”的评论,我相信Ankit正在寻找的是一种解决方案,即添加新的折扣代码不需要对处理其他不相关折扣代码的代码进行更改。乍一看,这很好,但真正的区别是什么,在将所有对写入巨型交换机或巨型数组填充块之间?@xtofl:OrderProcessor现在关闭以进行修改,并打开以进行扩展,这是OP所暗示的所需状态。此外,您还可以选择如何创建和查找所有TotalCalculator实现,例如,使用IoC容器配置它们或使用。我的意思是在我的回答中提到,实际上…更新了我的答案,使选项更加明显。上面的代码不符合要求
if(discountsDictionary == null)
{
discountsDictionary = LoadValuesFromXml(xmlFilePath);
}
if(discountsDictionary.ContainsKey(discountCode))
{
discount = discountsDictionary[discountCode];
discountedItemPrice = itemPrice * ( 1 - discount);
}
else
{
// Invalid discount code...
}
class OrderProcessor {
// Probably inject this or load it some other way than a static factory
private Collection<TotalCalculator> calculators = TotalCalculatorFactory.getTotalCalculators();
public Double calculateTotalPriceWithDiscountCode(Order order, char discountCode) {
for (TotalCalculator calculator : calculators) {
if (calculator.supports(discountCode)) {
return calculator.calculateTotal(order);
}
}
return order.getItemTotal();
}
}
class TotalCalculator {
private char discountCode;
private double discountRatio;
public TotalCalculator(char discountCode, double discountRatio) {
this.discountCode = discountCode;
this.discountRatio = discountRatio;
}
public boolean supports(char discountCode) {
return this.discountCode == discountCode;
}
public Double calculateTotal(Order order) {
return order.getItemTotal() - order.getItemTotal() * discountRatio;
}
}
class TotalCalculatorFactory {
public static Collection<TotalCalculator> getTotalCalculators() {
return Arrays.asList(
new TotalCalculator('A', 0.95),
new TotalCalculator('B', 0.15)
);
}
}
<discount-codes>
<discount-code>
<code>A</code>
<val>0.15</val>
</discount-code>
<discount-code>
<code>B</code>
<val>0.95</val>
</discount-code>
</discount-codes>
public class DiscountModel {
char code;
Double val;
// Implement getters and setters
}
public class DiscountParser {
List<DiscountModel> discountsList;
// Getters and Setters for discountsList
// Parser Code
public void parseDiscounts() {
// Code here
}
// Add new discount
public void addDiscount() {
// Code
}
// Remove discount
public void removeDiscount () {
// Code
}
}
/**
* Call this class when calculations need to be done.
*/
public class OrderProcessor {
// Declare instance of DocumentParser
DocumentParser dc1;
// Getter and setter for dc1
public Double calculateTotalPriceWithDiscountCode(Order order, char discountCode) {
// Find the corresponding discountcode and
// value from the list of values in the
// Class DocumentParser
// Use the corresponding values to calculate
// the discount and return the value
}
}