Как реализовать сопоставление с образцом в java и избежать instanceof? - PullRequest
3 голосов
/ 10 января 2020

В настоящее время я не знаю, как избежать запахов кода в моем фрагменте кода. Я попробовал несколько шаблонов (Стратегия, Посетитель), и они не предоставили чистого и удобного в обслуживании решения. Вот пример моего кода для шаблона стратегии:

public interface Strategy {
  <T> T foo(FirstParam firstParam, SecondParam secondParam);
}

public class StrategyOne implements Strategy {
  FirstReturnType foo(FirstParam firstParam, SecondParam secondParam);
}

public class StrategyTwo implements Strategy {
  SecondReturnType foo(FirstParam firstParam, SecondParam secondParam);
}

@Setter
public class Context {
    private Strategy strategy;
    public void execute(FirstParam firstParam, SecondParam secondParam) {
        if (strategy != null) {
            strategy.fo(firstParam, secondParam);
        }
    }
}

А есть пример объектов.

public abstract class Action {
 abstract void bar();
} 

public class ActionOne extends Action {
  void bar() {}
}

public class ActionTwo extends Action {
  void bar() {}
}

И я хочу сделать этот фрагмент кода чище

public class ActionExecutor {
   private Context context;
   private FirstParam firstParam;
   private SecondParam secondParam;
   public ActionExecutor(FirstParam firstParam, SecondParam secondParam) {
    this.context = new Context();
    this.firstParam = firstParam;
    this.secondParam = secondParam;
   }

  public void doSmth(Item item) {
    Action action = item.getAction();
    if(action instanceof ActionOne) {
     context.setStrategy(new StrategyOne());
    }
    if(action instanceof ActionTwo) {
     context.setStrategy(new StrategyTwo());
    }
    context.execute(firstParam, secondParam);
  }
}

Идея состоит в том, чтобы выполнить определенное c действие для определенного c типа объекта. Но я не знаю, как избежать использования instanceof в этой ситуации.

Ответы [ 3 ]

2 голосов
/ 10 января 2020

Может быть что-то вроде этого:

   public void doSmth(Item item) {

    Action action = item.getAction();

    Map<String,Strategy> strategies = new HashMap<>();
    strategies.put(ActionOne.getClass().getSimpleName(),new StrategyOne());
    strategies.put(ActionTwo.getClass().getSimpleName(),new StrategyTwo());
    ..
    strategies.put(ActionHundred.getClass().getSimpleName(),new StrategyHundred());

    if(strategies.containsKey(action.getClass().getSimpleName())) {
     context.setStrategy(strategies.get(action.getClass().getSimpleName()));
    }
    context.execute(firstParam, secondParam);  }
2 голосов
/ 10 января 2020

Два способа макушки моей головы.

public abstract class Action {
 public Strategy strategy;
 abstract void bar();
} 

public class ActionOne extends Action {
  void bar() {}
   // set strategy here,  possibly
}

public class ActionTwo extends Action {
  void bar() {}
}

public void doSmth(Item item) {
    Action action = item.getAction();
    action.strategy.execute(firstParam, secondParam);
  }

Второй способ - иметь перечисление во всех ваших действиях и принудительно указывать его как параметр в конструкторе абстрактного класса. Тогда просто используйте переключатель вместо instanceof

0 голосов
/ 10 января 2020

Это похоже на пример использования учебника для шаблона Factory Method . Вы можете использовать тот же код, который вы используете сейчас (или пример Map в другом ответе), но поместить его на заводе-изготовителе - тогда он будет определен для цели c и отделен от кода, который его использует.

Как-то так.

public class StrategyFactory {

    public static Stategy getStrategy(Action action) {
        if(action instanceof ActionOne) {
            return new StrategyOne();
        } else if(action instanceof ActionTwo) {
            return new StrategyTwo();
        }
    }
}

А потом, как-то так.

Action action = item.getAction();
action.setStrategy(StrategyFactory.getStrategy(action));

Здесь есть еще один пример: https://dzone.com/articles/design-patterns-the-strategy-and-factory-patterns

...