面向对象的编程 - 避免使用Switch / Case和If / else(JAVA)

时间:2015-07-20 13:48:40

标签: java object if-statement polymorphism

我遇到了一个问题,我不允许使用switch / case或if / else查询。

我收到了一个我读过的配置文件:

650;0;1.5;month
614;0;2.88;year
466;0;2.48;week
716;0;4.6;half-year
718;0;2.6;quarter

我将这些字符串拆分为“;”,因此将其保存在数组中。我遇到的问题是,我需要在代码中为代码中的其他内容执行其他操作ar [3],所以如果是一个月我还需要其他计算,那么当它是一整年时。

但我不允许用Switch / case或If / Else这样做,现在我感到困惑。

If (ar[3] = month){
do this;
else if (ar[3] = year) {
do this; 
}

我如何做这个面向对象的?感谢您的帮助:)

5 个答案:

答案 0 :(得分:2)

继承多态性是你的朋友

根据ar [3]中的时间段,您似乎需要某种继承结构。可以为每种情况编码特殊的do this方法。这样你就能够为每种情况做一些不同的事情。您只需要一种方法来首先实例化正确的子类型。有很多方法可以解决这个问题。

条件运算符

最直接的方法是恕我直言,条件算子?:

所以代码看起来像这样:

MyClass x = ar[3].equals("month") ? new MyClassMonth() :
            (ar[3].equals("year") ? new MyClassYear() :
            (ar[3].equals("week") ? new MyClassWeek() :
            (ar[3].equals("half-year") ? new MyClassHalfyear() :
                                        new MyClassQuarter())));
x.doSomething();

嵌套的条件表达式使您能够选择正确的类,继承为您提供所需的多态行为。

但您在评论中提到您也无法使用?:。下一步是什么?

无状态对象的地图

假设您编写了MyClassMonth,其中任何内容都不依赖于任何记忆状态,即doSomething()方法没有副作用。然后你可以创建一个Map<String, MyClass>来存储每个子类的一个实例,然后在你需要调用时将相关的一个拉出地图。

您可以像这样初始化地图:

final Map<String, MyClass> themap = new HashMap<>();
{
  themap.add("month", new MyClassMonth());
  themap.add("year", new MyClassYear());
  themap.add("week", new MyClassWeek());
  themap.add("half-year", new MyClassHalfyear());
  themap.add("quarter", new MyClassQuarter());
}

doSomething()作为参数调用ar

MyClass x = themap.get(ar[3]);
if (x != null)
  x.doSomething(ar);

其他选项

还有其他方法可以做到这一点。坚持使用Map概念,您可以将类文字存储在Map而不是实例中,然后反复实例化它们。你也可以在Map中保留一个lambda并调用它。

枚举

@OldCurmudgeon建议使用枚举。如果你将这些枚举放入Map并将一个lambda添加到枚举中,你可以获取枚举并调用lambda。这可行,并具有一定的吸引力,但似乎没有必要。你最好直接调用lambda。

答案 1 :(得分:2)

您可以使用 profile.setPreference("browser.download.folderList",2) profile.setPreference("browser.download.manager.showWhenStarting",false) profile.setPreference("browser.download.dir", new File("").getAbsolutePath()) profile.setPreference("browser.helperApps.neverAsk.saveToDisk","application/zip") 作为命令工厂模式,并使用enum查找实现选择。

Map

正确打印:

// Lookups for teh period.
static final Map<String, Period> lookup = new HashMap<>();

enum Period {

    Month("month") {

                @Override
                void process(int x, int y, double v) {
                    // Processing for "month" records here.
                    System.out.println(this + "-process(" + x + "," + y + "," + v + ")");
                }
            },
    Year("year") {
                @Override
                void process(int x, int y, double v) {
                    // Processing for "year" records here.
                    System.out.println(this + "-process(" + x + "," + y + "," + v + ")");
                }
            },
    Quarter("quarter") {
                @Override
                void process(int x, int y, double v) {
                    // Processing for "quarter" records here.
                    System.out.println(this + "-process(" + x + "," + y + "," + v + ")");
                }
            },
    HalfYear("half-year") {
                @Override
                void process(int x, int y, double v) {
                    // Processing for "half-year" records here.
                    System.out.println(this + "-process(" + x + "," + y + "," + v + ")");
                }
            };

    Period(String inData) {
        // Record me in the map.
        lookup.put(inData, this);
    }

    abstract void process(int x, int y, double v);

    static void process(String data) {
        String[] parts = data.split(";");
        Period p = lookup.get(parts[3]);
        if (p != null) {
            p.process(Integer.parseInt(parts[0]), Integer.parseInt(parts[1]), Double.parseDouble(parts[2]));
        }
    }
}

public void test() {
    String[] test = {"650;0;1.5;month",
        "614;0;2.88;year",
        "466;0;2.48;week",
        "716;0;4.6;half-year",
        "718;0;2.6;quarter",};
    for (String s : test) {
        Period.process(s);
    }
}

请注意,其中只有一个Month-process(650,0,1.5) Year-process(614,0,2.88) HalfYear-process(716,0,4.6) Quarter-process(718,0,2.6) ,但这只是防御以避免错误数据 - 它不是查找机制的一部分。

答案 2 :(得分:1)

这样的事情:

public interface Calculator {
    double calculate(int p1, int p2, double p3);
}

public class YearCalculator implements Calculator {
    public double calculate(int p1, int p2, double p3) {
        double value = 0.0;
        // do year calculations
        return value;
    }
}

public class CalculatorFactory {
    public Calculator getInstance(String type) {
       Calculator calculator = null;
       if (type != null) {
       } else {
           throw new IllegalArgumentException("calculator type cannot be null");
           if ("year".equalsIgnoreCase(type)) {
           } else {
               System.out.println(String.format("No such type: %s", type));
           }
       }
       return calculator;
    }
}

您必须在工厂中使用if / else逻辑,但在解析文本时则不行。

您的处理代码:

CalculatorFactory factory = new CalculatorFactory();
// contents is a List of Strings from your input file.
for (String line : contents) {
    String [] tokens = line.split(";");
    Calculator calculator = factory.getInstance(tokens[3]);
    double value = calculator.calculate(Integer.parseInt(tokens[0]), Integer.parseInt(tokens[1]), Double.parseDouble(tokens[2]));
}

答案 3 :(得分:0)

基于Codebender作为替代解决方案的建议:

您需要5个类,每个案例一个,具有通用接口但实现方式不同。

您的界面可能如下所示:

public interface MyCalculator {

    public double calculate(double a, double b, double c);

}

然后你需要实现与此类似的5个类。对于calculatemonthyearweekhalf-year,您需要针对quarter的不同实现使用不同的类:

public class MyMonthCalculator implements MyCalculator {

    @Override
    public double calculate(double a, double b, double c) {
        // Do your calculations here then return
    }

}

然后,在解析逻辑之前,您可以将五个类添加到Map

map.put("month", new MyMonthCalculator());
// Repeat for year, week, half-year and quarter

要实际执行计算:

double result = map.get(ar[3]).calculate(Double.parseDouble(ar[0]), Double.parseDouble(ar[1]), Double.parseDouble(ar[2]));

答案 4 :(得分:0)

您可以使用选项数组模拟ifcase。这里唯一的问题是在这样的数组中找到我们元素的索引。我们无法使用ifcase,但我认为while是一种选择。

所以你的代码可能类似于:

String[] options = { "foo", "bar", "baz" };
Runnable[] action = { new Runnable() {
    @Override
    public void run() {
        System.out.println("handling foo");
    }
}, new Runnable() {
    @Override
    public void run() {
        System.out.println("handling bar");
    }
}, new Runnable() {
    @Override
    public void run() {
        System.out.println("handling baz");
    }
} };
String choice = "bar";
int matched = 0;
int i = -1;
while (matched != 1) {
    i++;
    matched = boolToInt(options[i].equals(choice));
}
action[i].run();

我使用这样的方法将boolean转换为integer 1=true, 0=false

public static int boolToInt(Boolean b) {
    return 5 - b.toString().length();
}

相反,Runnable可以提供自己的界面。