Обобщить наследуемые классы в абстрактном JAVA
Нужно обобщить два класса. Есть абстрактный класс:
public abstract class AbstractRobot extends UpdatableUnit {
// --------------------------- Перемещение ------------------------------------
public abstract boolean canMoveTo(Cell to);
public abstract void move(Direction direct);
}
А также два наследующих класса:
public class StrongRobot extends AbstractRobot {
// --------------------------- Перемещение ------------------------------------
@Override
public boolean canMoveTo(Cell to) {return true;}
@Override
public void move(Direction direct) {
// Сделать вытаскивание предмета из ячейки, если ячейка не пустая, и переход в нее
Cell pos = typedOwner();
Cell newPos = pos.neighbor(direct);
if(newPos == null) {
return;
}
if(!canMoveTo(newPos)) {
newPos.extractUnit();
}
pos.extractUnit();
newPos.putUnit(this);
fireStateChanged();
}
// -----------------------------------------------------------------
@Override
public String toString() {
String msg;
msg = "R(∞)";
return msg;
}
}
И, соответственно:
public class SimpleRobot extends AbstractRobot {
// ------------------------------- Заряд ---------------------------------
private int _charge = 25;
private static final int REQUIRED_CHARGE_FOR_MOVE = 1;
public int charge() {
return _charge;
}
public boolean isAvailableCharge(int chargeQuery) {
return chargeQuery <= _charge;
}
protected int reduceCharge(int chargeQuery) {
int retrievedCharge = Math.min(_charge, chargeQuery);
_charge -= retrievedCharge;
return retrievedCharge;
}
// --------------------------- Перемещение ------------------------------------
@Override
public boolean canMoveTo(Cell to) {
return to.isEmpty();
}
@Override
public void move(Direction direct) {
Cell pos = typedOwner();
if(!isAvailableCharge(REQUIRED_CHARGE_FOR_MOVE)) {
return;
}
Cell newPos = pos.neighbor(direct);
if(newPos == null) {
return;
}
if(!canMoveTo(newPos)) {
return;
}
pos.extractUnit();
newPos.putUnit(this);
reduceCharge(REQUIRED_CHARGE_FOR_MOVE);
fireStateChanged();
}
// -----------------------------------------------------------------
@Override
public String toString() {
String msg;
msg = "R(" + charge() + ")";
return msg;
}
}
Как вы могли заметить, перемещение в этих двух классах совпадает на 80%. Цель - обобщить классы, то есть вынести в абстрактный класс перемещение.
Ответы (2 шт):
Во-первых, обобщение классов в Java обозначает скорее параметризацию класса неким общим типом T, то есть в названии класса появляется указание на общий (generic) тип: public abstract class AbstractRobot<T> extends UpdatableUnit<T>
В данном же случае требуется вынести некий общий функционал из реализаций абстрактных методов в класс-родитель, то есть использовать паттерн шаблонный метод (template method) для рефакторинга поведения в методе move.
Соответственно, метод move переносится в класс-родитель и перестаёт быть абстрактным, однако в нём должны быть добавлены вызовы других-методов, в которых следует реализовать "подшаги", чтобы можно было реализовать существующие различия в логике между реализациями StrongRobot и SimpleRobot.
Если "подшаги" определены как абстрактные методы, то их понадобится переопределять при помощи заглушек в классах, где они не требуются, поэтому может быть лучше определить эти заглушки в родительском классе.
public abstract class AbstractRobot extends UpdatableUnit {
public abstract boolean canMoveTo(Cell to);
public void move(Direction direct) {
if(!checkCondition()) {
return;
}
Cell pos = typedOwner();
Cell newPos = pos.neighbor(direct);
if(newPos == null) {
return;
}
if(!canMoveTo(newPos)) {
return;
}
pos.extractUnit();
newPos.putUnit(this);
afterMove();
fireStateChanged();
}
/**
Метод для проверки условия движения
@return true если движение разрешено
*/
protected boolean checkCondition() { return true; }
/**
Метод для вызова перед отправкой события stateChanged
*/
protected void afterMove() {}
}
Соответственно, реализация метода move в классе StrongRobot удаляется и заглушки для реализации шагов checkCondition / afterMove не нужны.
А в классе SimpleRobot потребуется переопределить только "подшаги":
public class SimpleRobot extends AbstractRobot {
// ...
@Override
protected boolean checkCondition() {
return isAvailableCharge(REQUIRED_CHARGE_FOR_MOVE);
}
@Override
protected void afterMove() {
reduceCharge(REQUIRED_CHARGE_FOR_MOVE);
}
}
Возможно, не лучший вариант, но можно сделать и так.
- В абстрактный класс помещаете метод
move()и выносите туда всё общее (В абстрактном классе могут быть неабстрактные методы). - В каждом классе-наследники переопределяете метод
move(), а первой строчкой вызываете метод из суперкласса с помощьюsuper():
public void move(Direction direct) {
super.move(direct);
//Какие-то специфичные действия для конкретного объекта
}