Передача в подкласс метода, но с суперклассом в качестве параметра?
У меня есть абстрактный класс Vehicle
с 2 реализованными подклассами RedVehicle
а также YellowVehicle
,
В другом классе у меня есть List<Vehicle>
содержащий экземпляры обоих подклассов. Я хочу иметь возможность передать в метод тип класса, а затем использовать этот тип, чтобы решить, с каким набором объектов я хочу что-то сделать в List
,
поскольку Class
в общем, я должен параметризовать его с чем-то, однако параметр в качестве родительского класса Vehicle
перестает работать вызывающий код с exampleMethod
теперь ожидает тип транспортного средства, а не подкласс RedVehicle
или же YellowVehicle
,
Я чувствую, что должен быть чистый способ сделать это так, каков был бы правильный способ реализовать функциональность?
NB Я не обязательно должен пройти в Class
типа, если есть лучшие предложения, я был бы рад попробовать их.
Телефонный код:
service.exampleMethod(RedVehicle.class);
service.exampleMethod(YellowVehicle.class);
Поля / Метод:
//List of vehicles
//Vehicle has 2 subclasses, RedVehicle and YellowVehicle
private List<Vehicle> vehicles;
//Having <Vehicle> as the Class parameter stops the calling code working
public void exampleMethod(Class<Vehicle> type)
{
for(Vehicle v : vehicles)
{
if(v.getClass().equals(type))
{
//do something
}
}
}
4 ответа
Сделайте это вместо этого:
public <T extends Vehicle> void exampleMethod(Class<T> type)
Почему вы не используете шаблон посетителя?
Таким образом, вы
- не нужны жетоны типа
- пусть динамическая диспетчеризация обрабатывает регистр различий (вместо
if(v.getClass().equals(type))
) - более гибки (следуя OCP)
В деталях:
ваш абстрактный класс Vehicle
получает метод accept(Visitor v)
с подклассами, реализующими это, вызывая соответствующий метод на v
,
public interface Visitor {
visitRedVehicle(RedVehicle red);
visitYellowVehicle(YellowVehicle yellow);
}
Использование посетителя:
public class Example {
public void useYellowOnly() {
exampleMethod(new Visitor() {
visitRedVehicle(RedVehicle red) {};
visitYellowVehicle(YellowVehicle yellow) {
//...action
});
}
public void exampleMethod(Visitor visitor){
for(Vehicle v : vehicles) {
v.accept(visitor);
}
}
}
Я обнаружил, что этот синтаксис работает должным образом:
public void exampleMethod(Class<? extends Vehicle> type)
Принятый ответ работает и привел меня туда, куда я хотел. Я подумал, что добавлю это, чтобы сделать его более понятным для всех, кому это может понадобиться.
В этом случае RevisedExposure является подклассом Exposure. Мне нужно вызвать GetMetadata() со списком любого из них, что приводит к тому же набору результатов.
private async Task<List<Metadata>> GetMetadata<T>(List<T> exposures) where T : Exposure
Теперь я могу вызвать этот метод из двух мест с разными версиями списка, как это.
var metadata = await GetExposureMetadata(revisions);
или же
var metadata = await GetExposureMetadata(exposures);
работает отлично!