Шаблон дизайна посетителя, Как работать с оператором If-else
Постановка задачи:
Существует три типа машин: Machine1 Machine2 и Machine3. Существует три типа валидаторов: ValidatorX, ValidatorY, ValidatorZ.
Каждый валидатор проверяет каждую машину по-разному.
Напишите классы Java, чтобы проектировать вышеупомянутую проблему.
Программа запускается из основной функции, в которой уже есть список валидаторов и машин. Каждый валидатор должен напечатать сообщение во время проверки
"Validator X валидационная машина Y";
Для этого прежде всего я создал один класс Machine и 3 разных класса Validator.
Machine.java
/**
* Machine
*
* @author sunny
*
*/
public class Machine {
private final String name;
public Machine(final String name) {
this.name = name;
}
public boolean validate(final Validator validator) {
return validator.validate(this);
}
public String getName() {
return name;
}
}
Validator.java
/**
* This is an abstract class for a Validator
*
* @author sunny
*
*/
public abstract class Validator {
private String name;
public Validator(final String name) {
this.name = name;
}
public boolean validate(final Machine machine) {
System.out.println("Validator " + getName() + " validating "
+ machine.getName());
// Here I need to write login corresponding to the machine name
// I need to write if machine Name is X then do this
// if machine name is Y then do this.
// I need to avoid this if else or switch case
// Is there any other better way to achieve this.
return true;
}
public String getName() {
return name;
}
}
ValidatorX.java
/**
* This is one ValidatorX class that I have created
*
* Similarly I have written ValidatorY and ValidatorZ classes
*
* @author sunny
*
*/
public class ValidatorX extends Validator {
public ValidatorX() {
super("X");
}
@Override
public boolean validate(Machine machine) {
super.validate(machine);
return true;
}
}
TestMain.java
import java.util.ArrayList;
import java.util.List;
/**
* Test class I have written to test this.
*
* @author sunny
*
*/
public class TestMain {
public static void main(String[] args) {
Validator[] validators = { new ValidatorX(), new ValidatorY(),
new ValidatorZ() };
List<Machine> machines = new ArrayList<Machine>();
machines.add(new Machine("Machine1"));
machines.add(new Machine("Machine2"));
machines.add(new Machine("Machine3"));
for (int i = 0; i < validators.length; i++) {
for (Machine machine : machines) {
validators[i].validate(machine);
}
}
}
}
В Validator.java (как вы можете видеть в комментариях) мне нужно написать логин, соответствующий имени машины, мне нужно написать, если имя машины - Machine1, затем сделать это, если имя машины - Machine2, а затем сделать это. Я должен избежать этого, если еще или переключить случай. Есть ли другой лучший способ добиться этого.
2 ответа
Ваше использование шаблона посетителя в порядке, проблема в классе машин.
Из того, что я вижу, класс вашей машины представляет "в зависимости" от имени, другой версии / типа машины. Таким образом, вам нужно if/else, чтобы идентифицировать машину и действовать соответственно.
Ваша проблема может быть решена с помощью абстракции
AbstractMachine - будет классом, представляющим общие функции для каждого типа / категории вашего компьютера>
Таким образом, в нем вы будете иметь по крайней мере следующие функции:
public boolean Validate (...)
public string GetName()
abstract public void MachineAction(...) = 0;
Поэтому вам придется написать класс Machine1, Machine2, Machine3, и вы будете обязаны "перегрузить" действие MachineAction для каждого дочернего класса.
Функция проверки вашего валидатора будет выглядеть так:
public boolean validate(final Machine machine)
{
System.out.println("Validator " + getName() + " validating "
+ machine.getName());
machine.MachineAction(...);
return true;
}
По своей конструкции это лучше, чем использование словаря (карты) функций, и вы всегда будете вызывать правильный.
++ Я бы действительно назвал имя лучше, чем Machine1, Machine2, Machine3 - здесь есть нечто большее, чем разница в "имени"
РЕДАКТИРОВАТЬ::
MachineA : Child Class (inherits from) Machine
//Since it inherits from Machine no need to reimplement
//Validate/GetName, but we need and it's obligated to
//reimplement MachineAction for this subclass.
override public void MachineAction(...)
{
DoThisMachineA();
}
private void DoThisMachineA(){...}
в то время как MachineB будет выглядеть так:
MachineB : Child Class (inherits from) Machine
//Since it inherits from Machine no need to reimplement
//Validate/GetName, but we need and it's obligated to
//reimplement MachineAction for this subclass.
override public void MachineAction(...)
{
DoThisMachineB();
}
private void DoThisMachineB(){...}
** Обратите внимание, что DoThisMachineB() не существует в классе MachineA и не будет представлен intellisense, и не будет компилироваться вообще, и наоборот.
Тем не менее, в посетителе все, что вам нужно сделать, это вызвать MachineAction(...), чтобы посетитель знал, что это машина, но не тот, какой дочерний тип машины, и какой бы тип машины вы ни использовали, вы будете действовать правильно. MachineAction(..) вызов. Вы можете прочитать об этом, мы называем это полиморфизмом.
Вы можете использовать карту действий.
Map<String, Action> actionMap = new HashMap<>();
actionMap.put("Machine1", new SomeActionOne());
actionMap.put("Machine2", new SomeActionTwo());
actionMap.put("Machine3", new SomeActionThree());
for (int i = 0; i < validators.length; i++) {
for (Machine machine : machines) {
validators[i].validate(machine);
Action action = actionMap.get(machine.getName());
assert action != null;
action.doSomething();
}
}