开关盒模式

Pattern for switch cases

我有一系列的switch case,但是好像有点太复杂了。简化它的最佳方法是什么?我在考虑使用策略设计模式。

我最初的想法是将 sendReport 变成一个方法,该方法从每个不同的 类 调用 sendReport。但是,我不确定如何实现它。谁能给我一些指导,也许还有一些建议,让我可以做些什么来简化这个 switch cases。

谢谢。

public static boolean sendReport(AuthToken token, Student client, List<ContactMethod> bestOptions, String data) {
    for (ContactMethod method : bestOptions) {
        switch (method) {
            case TEXT:
                String textMessage = client.getPhoneNumber();
                if (null != textMessage) {
                    TEXT.sendReport(token, client.getFName(), client.getLName(), data, textMessage);
                    return true;
                }
                break;
            case POST:
                String address = client.getAddress();
                String suburb = client.getSuburb();
                String state = client.getState();
                String postcode = client.getPostCode();
                if (null != address && null != suburb &&
                    null != state && null != postcode) {
                    Mail.sendReport(token, client.getFName(), client.getLName(), data, address, suburb, state, postcode);
                    return true;
                }
                break;
            case ELECTRONICMAIL:
                String email = client.getEmailAddress();
                if (null != email) {
                    Email.sendReport(token, client.getFName(), client.getLName(), data, email);
                    return true;
                }
                break;
            case VOICECALL:
                String number = client.getPhoneNumber();
                if (null != number) {
                    PhoneCall.sendReport(token, client.getFName(), client.getLName(), data, number);
                    return true;
                }
                break;
            case FACE_TO_FACE:
                String face2face = client.getFace2Face();
                String personName = client.getPersonName();
                if (null != face2face && null != personName) {
                    Face_To_Face.sendReport(token, client.getFName(), client.getLName(), data, face2face,personName);
                    return true;
                }
                break;
            case MAGIC:
                String magicID = client.getMagic();
                if (null != magicID) {
                    magic.sendReport(token, client.getFName(), client.getLName(), data, magicID);
                    return true;
                }
                break;
            default:
                return false;
        }
    }
    return false;
}

你甚至不需要设计模式,你只需要基本的多态性。

ContactMethod 从枚举更改为接口。每个 case 语句成为接口的实现

public class TextContactMethod implements ContactMethod { ... }    

sendReport 变为

for (ContactMethod method : bestOptions) {
    method.fooBar(token, client);
}

我只是将开关 "blocks" 转换为方法并调用它们;例如

public static boolean sendReport(AuthToken token, Student client, 
                                 List<ContactMethod> bestOptions,
                                 String data) {
    for (ContactMethod method : bestOptions) {
        boolean res;
        switch (method) {
            case TEXT:
                res = processText(token, client, data);
                break;
            case POST:
                res = processPost(token, client, data);
                break;
            ...
            default:
                res = false;
        }
        if (res) {
            return true;
        }
    }
    return false;
}

private boolean processText(AuthToken token, Student client) {
    String textMessage = client.getPhoneNumber();
    if (null != textMessage) {
        TEXT.sendReport(token, client.getFName(), client.getLName(), 
                        data, textMessage);
        return true;
    } else {
        return false;
    }
}

当然,您可以用设计模式来修饰它,但简单的过程抽象也同样有效。

定义一个具有 sendReport 方法的通用接口 ContactMethod,并为每个实现 ContactMethod 的开关案例创建不同的实现 类。例如;

public static boolean sendReport(AuthToken token, Student client, List<ContactMethod> bestOptions, String data) {
   for (ContactMethod method : bestOptions) {
      if (method.sendReport(token, client, data))
         return true;
   }
}

public class TextContactMethod implements ContactMethod {
    public boolean sendReport(AuthToken token, Student client, String data) {
            String textMessage = client.getPhoneNumber();
            if (null != textMessage) {
                TEXT.sendReport(token, client.getFName(), client.getLName(), data, textMessage);
                return true;
            }
       return false;
    }
}

是的,Strategy/Policy 模式的实现可以完成这项工作。基本上,三个已经存在的答案中的两个显示了该模式的可能实现 ( and ),尽管 Michael 认为他的实现不会遵循某种模式……

如果可能的联系方法集是固定的,您甚至可以将 sendReport() 作为方法添加到枚举中,每个枚举实例都有不同的实现。这为您节省了一个专门的策略注册表(并且您不需要定义多个不同的类)。

更清晰的路径是(如已经提到的答案所建议的那样)定义一个接口 ContactMethod 并为您需要的每种联系方式实现该接口。它的优点是您可以轻松添加其他联系方式(特别是如果您使用 java.util.ServiceLoader API)。

缺点是,如果联系方法是外部化实体的属性,则您需要某种类型的策略注册表以及从策略名称到它们的实现的映射——如前所述,您需要的东西当您扩展(滥用?)枚举时免费获得。