繁体   English   中英

如何避免重复的 if 语句

[英]How to avoid duplicated if statements

我有多个服务使用一种方法实现接口 - execute() 每个服务都使用此方法基于字符串值执行一些操作,在原始代码中,该值是枚举,因此这些值是常量。

interface Service{
   public void execute();
}

class Service1 implements Service{
   //constructors
   public void execute(JSONObject payload, String payloadType){
      if(payloadType.equals("type1")){
       doSomething(payload);
      }
   }
}

class Service2 implements Service{
   //constructors
   public void execute(JSONObject payload, String payloadType){
      if(payloadType.equals("type1")){
       doSomething1(payload);
      }
      if(payloadType.equals("type2")){
       doSomething2(payload);
      }
   }
}

我想避免每次创建新服务时都编写相同的 if 语句。 问题是,每个服务不必根据每个字符串类型执行操作。 所以Service1在type等于“type1”时执行动作,而Service2根据“type1”和“type2”执行动作。

我尝试了以下解决方案:

class Main {
  public static void main(String[] args) {
    exec(new B(), "type2");
  }

  private static void exec(Service service, JSONObject payload, String payloadType){
      if(payloadType.equals("type1")){
       Init i = (Init)service;
       i.init(payload);
      }
      if(payloadType.equals("type2")){
       Action a = (Action)service;
       a.action(payload);
      }
  }
}

interface Service{

}

interface Init{
  public void init(JSONObject payload);
}

interface Action{
  public void action(JSONObject payload);
}

class A implements Service, Init{
  @Override
  public void init(JSONObject payload){
    doSomething(payload);
  }
}

class B implements Service, Init, Action{

  @Override
  public void init(JSONObject payload){
    doSomething1(payload);
  }

 @Override
   public void action(JSONObject payload){
    doSomething2(payload);
  }
}

上面的代码有效,但我不喜欢使用强制转换。 我认为这不是一个好习惯,也很不安全。 您能否建议,我可以在这里使用什么设计模式或其他解决方案? 我尝试了访问者,但我无法在这种情况下找出正确的实现方式。

更新

感谢所有的答案,他们非常有帮助。 我设法实现了我想要的。 这是最终有效的代码。

public class Main {

    public static B b = new B();
    public static A a = new A();

    public static void main(String[] args) {
        exec(b, "init");
    }

    private static void exec(Service service, String type){
        if(type.equals("init") && service instanceof Init){
            service.fillCarrier(new InitCarrier());
        }
        if(type.equals("action") && service instanceof Action){
            service.fillCarrier(new ActionCarrier());
        }
    }
}

interface Carrier<T>{
    public void set(T t);
}

class InitCarrier implements Carrier<Init>{
    public void set(Init init){
        init.init();
    }
}

class ActionCarrier implements Carrier<Action>{
    public void set(Action action){
        action.action();
    }
}

abstract class Service{
    public void fillCarrier(Carrier carrier){
        carrier.set(this);
    }
}

interface Init{
    public void init();
}

interface Action {
    public void action();
}

class A extends Service implements Init{
    
    @Override
    public void init(){
        System.out.println("init a");
    }
}

class B extends Service implements Init, Action{

    @Override
    public void init() {
        System.out.println("init b");
    }

    @Override
    public void action(){
        System.out.println("action");
    }
}

为了达到这个要求,我们需要进行模式化。

  1. 工厂模式。
  2. 战略模式。

TypeFactory 根据我们提供的字符串创建一个TypeFactory 每个Type实现都以自己的方式实现doSomething()方法。 (这里使用工厂模式)

类型策略:

interface Type{
    public void doSomething();
}

class TypeOne implements Type{
    @Override
    public void doSomething() {
        System.out.println("Type One!");    
    }
}

class TypeTwo implements Type{
    @Override
    public void doSomething() {
        System.out.println("Type Two!");
        
    }
}

型厂:

class TypeFactory{
    Type type;
    public Type createType(String condition) {
        if (condition == null || condition.isEmpty()) {
            return null;
        }
        if ("type1".equals(condition)) {
            return new TypeOne();
        }
        else if ("type2".equals(condition)) {
            return new TypeTwo();
        }
        return null;
    }
}

现在要实现最终目标,我们需要声明一个带有execute方法的Service接口。 execute方法将Type作为输入参数。 根据您实际传递的type ,将调用相应的doSometing方法。 (仅使用策略模式)

interface Service{
    public void execute(Type type);
}

class ServiceOne implements Service{

    @Override
    public void execute(Type type) {
        System.out.print("Service One - ");
        type.doSomething();
        
    }
}

class ServiceTwo implements Service{

    @Override
    public void execute(Type type) {
        System.out.print("Service Two - ");
        type.doSomething();
        
    }
}

主要的 Class 看起来像这样:

public class DesignPatternCombo {

    public static void main(String[] args) {
        
        Type typeOne = new TypeFactory().createType("type1");
        Type typeTwo =  new TypeFactory().createType("type2");
        
        Service serviceOne = new ServiceOne();
        serviceOne.execute(typeOne);
        
        Service serviceTwo = new ServiceTwo();
        serviceTwo.execute(typeOne);
        serviceTwo.execute(typeTwo);

    }

}

预期 output:

Service One - Type One!
Service Two - Type One!
Service Two - Type Two!

棘手的问题,我可能有一个可行的解决方案。

那就是存储类型,类型的代码以 HashMap 的形式存储。

HashMap<String, Function<Void, Void>> types = new HashMap<String, Function<Void, Void>>();

然后在主 function 中,您将使用类型名称填充 HashMap,然后运行 function。

types.put("Type1",()->{
    /*Do something*/
});
types.put("Type2",()->{
    /*Do something*/
});
types.put("Type3",()->{
    /*Do something*/
});

然后在服务中,您将拥有一个字符串数组,用于表示它使用的类型。 如:

String[] serviceTypes = {"Type1", "Type2"};

最后,在服务的执行 function 中,您将运行相应的 lambda 到字符串。

public void execute(String type){
    if((new ArrayList<>(Arrays.asList(serviceTypes))).contains(type)) {
        Main.types.get(type);
    }
}

您可以使用抽象基础 class。

基础 class 实现 Service 并具有 execute() 方法。 它不能绕过 if 语句,但毕竟它可以有一个允许值的列表,并且只要类型参数包含在列表中,它就会调用另一个方法。 默认情况下,该方法什么都不做。

基础的简洁子类不再需要执行 if 条件,因为它们只是覆盖基础 class 中的单个方法。 所以这适用于一大堆非常相似的服务。 这种方法的优点是,如果您有一些奇特的、不兼容的服务类型,您可以通过直接覆盖 execute() 方法来跳过 if 语句。 所以这种模式是可扩展的,这可能比保存更多的 if 语句更有价值。

您可以使用策略设计模式优雅地解决这个问题。

  1. 创建一个名为Strategy的通用接口
interface Strategy {
  void execute(JSONObject payload);
}

  1. 根据您的需要创建Strategy的多个实现:
class ServiceType1 implements Strategy {
  //constructors and fields
  @Override
  public void execute(JSONObject payload) {
    //code to be executed for "type1"
  }
}

class ServiceType2 implements Strategy {
  //constructors and fields
  @Override
  public void execute(JSONObject payload) {
    //code to be executed for "type2"
  }
}

...
  1. 按类型对服务实现进行分组,例如:
Map<String, Strategy> strategyMap = new HashMap<>();
strategyMap.put("type1", new ServiceType1());
strategyMap.put("type2", new ServiceType2());
...
  1. 无需任何 if 语句即可调用所需的服务,如下所示:
private static void exec(String payloadType, JSONObject payload) {
  strategyMap.get(payloadType).execute(payload);
}

PS:如果Strategy的所有实现共享一些共同行为,您可以将Strategyinterface转换为abstract class并将共同行为移到那里。

哇,你的架构看起来很复杂。 你应该考虑更好的层次结构。 但如果你不能,你为什么不在 Service 上创建一个方法,让子类型决定他们想要什么行为。 然后您可以从 Service 调用该方法来执行

static class Main {
        
        public static void main(String[] args) {
            exec(new B());
        }

        private static void exec(Service service){
            service.execute();
        }
    }

    interface Service{
        void execute();
    }
    
    interface Init{
        public void init();
    }

    interface Action{
        public void action();
    }

    static class A implements Service, Init{
        @Override
        public void init(){
            System.out.println("init a");
        }

        @Override
        public void execute(){
            init();
        }
    }

    static class B implements Service, Init, Action{

        @Override
        public void init(){
            System.out.println("init b");
        }

        @Override
        public void action(){
            System.out.println("action");
        }

        @Override
        public void execute(){
            action();
        }
    }

将公共逻辑提取到单独的 class 怎么样? 云是:

  • BaseService和所有其他服务都应该实现这一点;
  • ServiceDelegate和所有其他服务应将所有工作委托给该服务。

下面的代码片段提供了第一个解决方案。

// This is you Service interface
public interface Service {

    void execute(JSONObject payload, String payloadType);
}
// This is base implementation. Use `Map` to replace `if` statements
public abstract class BaseService implements Service {

    private static final Consumer<JSONObject> NULL = jsonObject -> { };

    private final Map<String, Consumer<JSONObject>> consumers;

    protected BaseService(Map<String, Consumer<JSONObject>> consumers) {
        this.consumers = consumers == null || consumers.isEmpty() ? Map.of()
                                : Collections.unmodifiableMap(consumers);
    }

    @Override
    public final void execute(JSONObject payload, String payloadType) {
        consumers.getOrDefault(payloadType, NULL).accept(payload);
    }
}
public class ConcreteService extends BaseService {

    private static final Consumer<JSONObject> DO_SOMETHING_TYPE1 = jsonObject -> {
        // TODO implementation for "type1"
    };

    private static final Consumer<JSONObject> DO_SOMETHING_TYPE2 = jsonObject -> {
        // TODO implementation for "type2"
    };

    public ConcreteService() {
        super(Map.of(
                "type1", DO_SOMETHING_TYPE1,
                "type2", DO_SOMETHING_TYPE2));
    }
} 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM