有没有其他方法可以在Java中实现一个switch case,而不是其他看起来不好的if。一组值将组合在一起,根据选择相应的方法必须执行。
答案 0 :(得分:26)
如果您的代码周围有大量的开关/案例陈述,它们会让您发疯。
您可以选择重构: Replace conditional with polymorphism.
假设您有一个用于将信息保存到不同设备的软件:定义了4个持久性操作: 获取,保存,删除,更新 ,其中可以通过N个持久性机制(平面文件,网络,RDBMS,XML等)实现。
你的代码必须全部支持它们,所以你可以在4个不同的地方支持它们:
<强> BEFORE 强>
class YourProblematicClass {
....
public void fetchData( Object criteria ) {
switch ( this.persitanceType ) {
case FilePersistance:
// open file
// read it
// find the criteria
// build the data
// close it.
break;
case NetWorkPersistance:
// Connect to the server
// Authenticate
// retrieve the data
// build the data
// close connection
break();
case DataBasePersistace:
// Get a jdbc connection
// create the query
// execute the query
// fetch and build data
// close connection
break;
}
return data;
}
保存/删除/更新相同
public void saveData( Object data) {
switch ( this.persitanceType ) {
case FilePersistance:
// open file, go to EOF, write etc.
break;
case NetWorkPersistance:
// Connect to the server
// Authenticate
// etc
break();
case DataBasePersistace:
// Get a jdbc connection, query, execute...
break;
}
}
依旧......
public void deleteData( Object data) {
switch ( this.persitanceType ) {
case FilePersistance:
break;
case NetWorkPersistance:
break();
case DataBasePersistace:
break;
}
}
public void updateData( Object data) {
switch ( this.persitanceType ) {
case FilePersistance:
break;
case NetWorkPersistance:
break();
case DataBasePersistace:
break;
}
}
使用switch / case语句会出现问题:
每次要添加新类型时,都必须在每个部分插入新的开关/案例。
很多时候,有些类型是相似的,它们不需要不同的开关/案例(你可以级联它们)
因此,这里的重构将是添加接口或抽象类型,并使不同的类型实现该接口并将责任委托给该对象。
所以你会有这样的事情:
<强> AFTER 强>
public interface PersistenceManager {
public void fetchData( Object criteria );
public void saveData( Object toSave );
public void deleteData( Object toDelete );
public void updateData( Object toUpdate );
}
不同的实现
public class FilePersistence implements PersistanceManager {
public void fetchData( Object criteria ) {
// open file
// read it
// find the criteria
// build the data
// close it.
}
public void saveData( Object toSave ) {
// open file, go to EOF etc.
}
public void deleteData( Object toDelete ){
....
}
public void updateData( Object toUpdate ){
....
}
}
其他类型将根据其逻辑实现。网络将处理套接字和流,DB将处理JDBC,ResultSets等XML与节点等。
public class NetworkPersistence implements PersistanceManager {
public void fetchData( Object criteria ) {
// Socket stuff
}
public void saveData( Object toSave ) {
// Socket stuff
}
public void deleteData( Object toDelete ){
// Socket stuff
}
public void updateData( Object toUpdate ){
// Socket stuff
}
}
public class DataBasePersistence implements PersistanceManager {
public void fetchData( Object criteria ) {
// JDBC stuff
}
public void saveData( Object toSave ) {
// JDBC stuff
}
public void deleteData( Object toDelete ){
// JDBC stuff
}
public void updateData( Object toUpdate ){
// JDBC stuff
}
}
最后你只需要委托调用。
随后:
public YouProblematicClass { // not longer that problematic
PersistamceManager persistance = // initialize with the right one.
public void fetchData( Object criteria ) {
// remove the switch and replace it with:
this.persistance.fetchData( criteria );
}
public void saveData( Object toSave ) {
// switch removed
this.persistance.saveData( toSave );
}
public void deleteData( Object toDelete ){
this.persistance.deleteData( toDelete );
}
public void updateData( Object toUpdate ){
this.persistance.updateData( toUpdate );
}
}
因此,您只需根据类型仅为持久性管理器创建一次正确的实例。然后通过多态来解决所有调用。这是面向对象技术的关键特性之一。
如果您决定需要另一个持久性管理器,则只需创建新实现并分配给该类。
public WavePersistance implements PersistanceManager {
public void fetchData( Object criteria ) {
// ....
}
public void saveData( Object toSave ) {
// ....
}
public void deleteData( Object toDelete ){
// ....
}
public void updateData( Object toUpdate ){
// ....
}
}
答案 1 :(得分:16)
据推测,你正在努力解决案件不变的要求。通常这是代码味道,但有些事情你可以做。您可能希望提出并链接到另一个问题,详细说明您尝试切换的原因。
Map<String,Object> map = new HasMap<String,Object>();
// ... insert stuff into map
// eg: map.add("something", new MyObject());
String key = "something";
if (map.contains(key)) {
Object o = map.get(key);
}
在上面的示例中,您可能希望映射到“处理程序”,例如
interface Handler {
public void doSomething();
}
然后将其全部变为查找。
if (map.contains(key)) { map.get(key).doSomething(); }
再次,这有点气味,所以请发一个说明推理的问题。
答案 2 :(得分:5)
重构代码以使用多态可以摆脱对switch语句的需求。但是,切换有一些合法用途,因此取决于您的情况。
答案 3 :(得分:1)
一系列丑陋的if,else if,else
?
答案 4 :(得分:1)
或者可以想象一种动态切换案例:
public interface Task<T>
{
public void doSomething(T context);
}
public Class SwitchCase<T>
{
Map<Integer,Task<T>> tasks;
Task<T> defaultTask;
public void choose(int choice, T context)
{
Task<T> t= this.tasks.get(choice);
if(t!=null) { t.doSomething(context); return;}
if(defaultTask!=null) { defaultTask.doSomething(context);}
}
}
答案 5 :(得分:1)
我猜“清洁代码”根据switch / case与if / else有一个很好的章节。
此外:我认为通过使用switch case,polymorphism甚至是一个好的'if / else来决定是否可以减少“噪音”并使代码更清晰是有意义的。我想,案件的数量在这里发挥了重要作用。
答案 6 :(得分:1)
我发布了一个典型案例,我如何用枚举替换switch case。
在重构之前我有枚举PatternTypes
:
public enum PatternTypes {
ALPHA_CHAR, ALPHANUMERIC_CHAR, ADDITIONAL_CHAR, UNICODE_BMP_CHARS
}
和功能:
private static final String ALPHA_CHAR = "[a-zA-Z]+";
private static final String ALPHANUMERIC_CHAR = "[a-zA-Z0-9\\_]+";
private static final String ADDITIONAL_CHAR = "[a-zA-Z0-9\\_\\-\\,\\.\\s\\!\\#\\$\\&\\(\\)\\*\\+\\;\\:\\=\\?\\@\\|\\[\\]\\{\\}\\~]+";
private static final String UNICODE_BMP_CHARS = "[a-zA-Z0-9\\_\\-\\,\\.\\s\\!\\#\\$\\&\\(\\)\\*\\+\\;\\:\\=\\?\\@\\|\\[\\]\\{\\}\\~\u00A0-\uD7FF\uF900-\uFFFD]+";
/*
* Match given classAbbr with given RegEx pattern
*/
private void checkInvalidClassAbbr(String classAbbr,
PatternTypes classAbbrPattern) {
switch (classAbbrPattern) {
case ALPHA_CHAR:
checkUnmatched(classAbbr, ALPHA_CHAR, CLASS_ABBR_VAR_NAME);
break;
case ALPHANUMERIC_CHAR:
checkUnmatched(classAbbr, ALPHANUMERIC_CHAR, CLASS_ABBR_VAR_NAME);
break;
case ADDITIONAL_CHAR:
throw new MalFormedDNException("Not support Pattern Type:"
+ classAbbrPattern);
case UNICODE_BMP_CHARS:
throw new MalFormedDNException("Not support Pattern Type:"
+ classAbbrPattern);
}
}
将重构PatternTypes
修改为:
public enum PatternTypes {
/**
* RegEx patterns divided by restriction level
*/
ALPHA_CHAR("[a-zA-Z]+"),
ALPHANUMERIC_CHAR("[a-zA-Z0-9\\_]+"),
ADDITIONAL_CHAR("[a-zA-Z0-9\\_\\-\\,\\.\\s\\!\\#\\$\\&\\(\\)\\*\\+\\;\\:\\=\\?\\@\\|\\[\\]\\{\\}\\~]+"),
UNICODE_BMP_CHARS("[a-zA-Z0-9\\_\\-\\,\\.\\s\\!\\#\\$\\&\\(\\)\\*\\+\\;\\:\\=\\?\\@\\|\\[\\]\\{\\}\\~\u00A0-\uD7FF\uF900-\uFFFD]+");
public String getPatternContent() {
return patternContent;
}
private String patternContent;
PatternTypes(String patternContent) {
this.patternContent = patternContent;
}
}
和功能简化为:
/*
* Match given classAbbr with given RegEx pattern
*/
private void checkInvalidClassAbbr(String classAbbr, PatternTypes classAbbrPattern) {
if (PatternTypes.ADDITIONAL_CHAR.equals(classAbbrPattern) || PatternTypes.UNICODE_BMP_CHARS.equals(classAbbrPattern)){
throw new MalFormedDNException("RegEx pattern:" + classAbbrPattern.name() + "is not allowed for Class Abbr");
}
checkUnmatched(classAbbr, classAbbrPattern.getPatternContent(), CLASS_ABBR_VAR_NAME);
}
答案 7 :(得分:1)
Hashmap被认为不具有内存友好性,因此您可以将Enum用于此目的。
示例:
class EnumExample4{
enum Season{
WINTER(5), SPRING(10), SUMMER(15), FALL(20);
private int value;
private Season(int value){
this.value=value;
}
}
public static void main(String args[]){
System.out.println(Season.WINTER.value); //This gives you 5
}}
这将使您免于编写Switch Case或if语句。
答案 8 :(得分:1)
对于switch语句的替代方法,我认为最佳解决方案是使用枚举。例如:考虑以下情况: -
public enum EnumExample {
OPTION1{
public double execute() {
Log.info(CLASS_NAME, "execute", "The is the first option.");
return void;
}
},
OPTION2{
public double execute() {
Log.info(CLASS_NAME, "execute", "The is the second option.");
return void;
}
},
OPTION3{
public double execute() {
Log.info(CLASS_NAME, "execute", "The is the third option.");
return void;
};
public static final String CLASS_NAME = Indicator.class.getName();
public abstract void execute();
}
上述枚举可以按以下方式使用:
EnumExample.OPTION1.execute();
希望这可以帮助你们。
答案 9 :(得分:0)
你想做什么?为什么Switch-Case不够好?
快速回答是:使用if-else
答案 10 :(得分:0)
if () {}
else if () {}
...
else if () {}
但我不会说它更好......
答案 11 :(得分:0)
if
(以及else if
和else
)声明怎么样?虽然switch
只允许您使用相等于整数或枚举类型进行切换,但if
允许您使用任何布尔逻辑。
答案 12 :(得分:0)
您总是可以用if-else if-else if-else if...
替换开关,但我不明白您为什么要这样做。根据上下文switch
,有时也可以用数组或散列图代替。
答案 13 :(得分:0)
如果字符串是静态的,您可以创建一个ENUM。 然后切换它。