面向对象编程 - 避免 Switch/Case 和 If/else (JAVA)
Object Oriented Programming - Avoid Switch/Case and If/else (JAVA)
我遇到一个问题,不允许我使用 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;
}
我如何做这个面向对象的?感谢您的帮助:)
继承多态性是你的朋友
看来您需要某种基于 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();
嵌套的条件表达式让你能够select正确的class,继承给你你想要的多态行为。
但是你在评论中提到你也不能使用?:
。下一步是什么?
无状态对象图
假设您以一种不依赖任何记忆状态的方式编写 MyClassMonth
,即 doSomething()
方法没有副作用。然后你可以创建一个 Map<String, MyClass>
来存储每个子 class 的一个实例,然后在你需要调用时从映射中拉出相关的实例。
您可以像这样初始化地图:
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());
}
并以 ar
作为参数调用 doSomething()
:
MyClass x = themap.get(ar[3]);
if (x != null)
x.doSomething(ar);
其他选项
还有其他方法可以做到这一点。坚持 Map
概念,您可以将 class 文字而不是实例存储在 Map
中,然后以反射方式实例化它们。您还可以在 Map
中保留一个 lambda 并调用它。
枚举
@OldCurmudgeon 建议使用枚举。如果将这些枚举放入 Map
并向枚举添加 lambda,则可以获取枚举并调用 lambda。那会起作用并且具有一定的吸引力,但似乎没有必要。你最好直接调用 lambda。
像这样:
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]));
}
根据 Codebender 给出的建议作为替代解决方案:
您需要 5 个 class,每种情况一个,具有通用接口但不同实现。
您的界面可能如下所示:
public interface MyCalculator {
public double calculate(double a, double b, double c);
}
然后您将需要实现与此类似的 5 个 classes。对于 month
、year
、week
、half-year
和 quarter
,您将需要不同的 class 和 calculate
的不同实现:
public class MyMonthCalculator implements MyCalculator {
@Override
public double calculate(double a, double b, double c) {
// Do your calculations here then return
}
}
然后,在您的解析逻辑之前,您可以将五个 class 添加到 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]));
您可以使用 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)
请注意,其中有一个 if
,但这只是为了避免错误数据的防御 - 它不是查找机制的一部分。
您可以使用选项数组模拟 if
或 case
。这里唯一的问题是在这样的数组中找到我们元素的索引。我们不能使用 if
和 case
但我认为 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。
我遇到一个问题,不允许我使用 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;
}
我如何做这个面向对象的?感谢您的帮助:)
继承多态性是你的朋友
看来您需要某种基于 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();
嵌套的条件表达式让你能够select正确的class,继承给你你想要的多态行为。
但是你在评论中提到你也不能使用?:
。下一步是什么?
无状态对象图
假设您以一种不依赖任何记忆状态的方式编写 MyClassMonth
,即 doSomething()
方法没有副作用。然后你可以创建一个 Map<String, MyClass>
来存储每个子 class 的一个实例,然后在你需要调用时从映射中拉出相关的实例。
您可以像这样初始化地图:
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());
}
并以 ar
作为参数调用 doSomething()
:
MyClass x = themap.get(ar[3]);
if (x != null)
x.doSomething(ar);
其他选项
还有其他方法可以做到这一点。坚持 Map
概念,您可以将 class 文字而不是实例存储在 Map
中,然后以反射方式实例化它们。您还可以在 Map
中保留一个 lambda 并调用它。
枚举
@OldCurmudgeon 建议使用枚举。如果将这些枚举放入 Map
并向枚举添加 lambda,则可以获取枚举并调用 lambda。那会起作用并且具有一定的吸引力,但似乎没有必要。你最好直接调用 lambda。
像这样:
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]));
}
根据 Codebender 给出的建议作为替代解决方案:
您需要 5 个 class,每种情况一个,具有通用接口但不同实现。
您的界面可能如下所示:
public interface MyCalculator {
public double calculate(double a, double b, double c);
}
然后您将需要实现与此类似的 5 个 classes。对于 month
、year
、week
、half-year
和 quarter
,您将需要不同的 class 和 calculate
的不同实现:
public class MyMonthCalculator implements MyCalculator {
@Override
public double calculate(double a, double b, double c) {
// Do your calculations here then return
}
}
然后,在您的解析逻辑之前,您可以将五个 class 添加到 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]));
您可以使用 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)
请注意,其中有一个 if
,但这只是为了避免错误数据的防御 - 它不是查找机制的一部分。
您可以使用选项数组模拟 if
或 case
。这里唯一的问题是在这样的数组中找到我们元素的索引。我们不能使用 if
和 case
但我认为 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。