在 Java 中充分利用多态性
Getting The Best Out of Polymorphism in Java
我有以下问题:
假设我们有 3 个 classes :
- 一篇摘要 class 名为
Vehicle
- 一个名为
Motorcycle
的 class 扩展了 Vehicle
- 一个名为
Car
的 class 扩展了 Vehicle
这意味着 Vehicle
个对象可以容纳 Motorcycle
和 Car
个对象。
我还有一个名为 VehicleDatabase
的 class,它基本上 "simulates" 一个数据库(我希望我可以使用数据库,但这是一个大学项目)并拥有一个 ArrayList<Vehicle>
名为 db
的字段以及提供一些基本操作的一些方法,以便我可以与数据库交互(CRUD 操作和其他一些)。
我想要实现的一种方法是 showVehicles()
。为了简化并直达我的问题,假设此方法必须简单地将函数参数指定的所有对象的 .toString()
打印到控制台。
示例:
用户中出现一个菜单:
Select which type of vehicles you want to be shown:
1.Motorcycles
2.Cars
Make your choice:
之后我们的函数 showVehicles
必须接受一个参数,例如 showVehicles(CarSomething)
并打印存储在 db
ArrayList 中的所有汽车。我真的找不到更优雅的方法来实现该功能。下面是我当前的实现:
public void showVehicles(Class<?> cls)
{
for(Vehicle v : db)
{
if(v.getClass().equals(cls))
System.out.println(v.toString());
}
}
并像这样调用它:showVehicles(Car.class)
或 showVehicles(Motorcycle.class)
.
有更好的方法吗?请提出您的建议。我只是觉得我没有按应有的方式使用多态性。
实际上,这不是通常使用面向对象方法的方式。这是一个使用多态方法的示例。 'printName' 函数在抽象 class 中定义(在这种情况下也可以是接口):
import java.util.ArrayList;
abstract class Vehicle {
public abstract void printName(); // virtual function
}
class Car extends Vehicle {
public void printName() { // function implementation in the class Car
System.out.println("I am a car");
}
}
class Bike extends Vehicle {
public void printName() { // function implementation int the class Bike
System.out.println("I am a bike");
}
}
public class T1{
ArrayList <Vehicle> vehicles = new ArrayList<Vehicle>();
void create() {
vehicles.add(new Car());
vehicles.add(new Bike());
}
void list() {
for (Vehicle v: vehicles)
v.printName(); // use the function at the show time
}
public static void main(String args[]) {
T1 t1 = new T1();
t1.create();
t1.list();
}
}
如果要使用真实的数据库会有很大的区别。后者只能保存java class 中的data
字段并将它们恢复到class 中。因此,您的应用程序必须在读取时了解 classes,并确保正确的 classes 填充了正确的数据。在这种情况下,序列化可以提供帮助。
这是一种可能。
我创建了一个 Map<Class<?>, List<Vehicle>>
来保存库存。
该地图是根据车辆列表创建的,但可以通过直接直接添加到地图来创建。
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
abstract class Vehicle {
}
class MotorCycle extends Vehicle {
String name;
MotorCycle(String name) {
this.name = name;
}
public String toString() {
return name;
}
}
class Car extends Vehicle {
String name;
Car(String name) {
this.name = name;
}
public String toString() {
return name;
}
}
public class CarMapper {
public static void main(String[] args) {
List<Vehicle> list = new ArrayList<>();
list.add(new MotorCycle("Honda"));
list.add(new MotorCycle("Harley-Davidson"));
list.add(new Car("Ford"));
list.add(new Car("Chrysler"));
Map<Class<?>, List<Vehicle>> inventory = list.stream().collect(
Collectors.groupingBy(Object::getClass));
}
}
这是否合理取决于您(以及评论的其他人)。您可能仍需要地图才能从用户菜单中获得正确的 class。
Map<String, Class<?>> menuMap = new HashMap<>();
menuMap.put("Car", Car.class);
menuMap.put("MotorCycle", MotorCycle.class);
Class<?> lookup = menuMap.get("Car");
for (Vehicle v : inventory.get(lookup)) {
System.out.println(v.toString());
}
我有以下问题:
假设我们有 3 个 classes :
- 一篇摘要 class 名为
Vehicle
- 一个名为
Motorcycle
的 class 扩展了Vehicle
- 一个名为
Car
的 class 扩展了Vehicle
这意味着 Vehicle
个对象可以容纳 Motorcycle
和 Car
个对象。
我还有一个名为 VehicleDatabase
的 class,它基本上 "simulates" 一个数据库(我希望我可以使用数据库,但这是一个大学项目)并拥有一个 ArrayList<Vehicle>
名为 db
的字段以及提供一些基本操作的一些方法,以便我可以与数据库交互(CRUD 操作和其他一些)。
我想要实现的一种方法是 showVehicles()
。为了简化并直达我的问题,假设此方法必须简单地将函数参数指定的所有对象的 .toString()
打印到控制台。
示例:
用户中出现一个菜单:
Select which type of vehicles you want to be shown:
1.Motorcycles
2.Cars
Make your choice:
之后我们的函数 showVehicles
必须接受一个参数,例如 showVehicles(CarSomething)
并打印存储在 db
ArrayList 中的所有汽车。我真的找不到更优雅的方法来实现该功能。下面是我当前的实现:
public void showVehicles(Class<?> cls)
{
for(Vehicle v : db)
{
if(v.getClass().equals(cls))
System.out.println(v.toString());
}
}
并像这样调用它:showVehicles(Car.class)
或 showVehicles(Motorcycle.class)
.
有更好的方法吗?请提出您的建议。我只是觉得我没有按应有的方式使用多态性。
实际上,这不是通常使用面向对象方法的方式。这是一个使用多态方法的示例。 'printName' 函数在抽象 class 中定义(在这种情况下也可以是接口):
import java.util.ArrayList;
abstract class Vehicle {
public abstract void printName(); // virtual function
}
class Car extends Vehicle {
public void printName() { // function implementation in the class Car
System.out.println("I am a car");
}
}
class Bike extends Vehicle {
public void printName() { // function implementation int the class Bike
System.out.println("I am a bike");
}
}
public class T1{
ArrayList <Vehicle> vehicles = new ArrayList<Vehicle>();
void create() {
vehicles.add(new Car());
vehicles.add(new Bike());
}
void list() {
for (Vehicle v: vehicles)
v.printName(); // use the function at the show time
}
public static void main(String args[]) {
T1 t1 = new T1();
t1.create();
t1.list();
}
}
如果要使用真实的数据库会有很大的区别。后者只能保存java class 中的data
字段并将它们恢复到class 中。因此,您的应用程序必须在读取时了解 classes,并确保正确的 classes 填充了正确的数据。在这种情况下,序列化可以提供帮助。
这是一种可能。
我创建了一个 Map<Class<?>, List<Vehicle>>
来保存库存。
该地图是根据车辆列表创建的,但可以通过直接直接添加到地图来创建。
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
abstract class Vehicle {
}
class MotorCycle extends Vehicle {
String name;
MotorCycle(String name) {
this.name = name;
}
public String toString() {
return name;
}
}
class Car extends Vehicle {
String name;
Car(String name) {
this.name = name;
}
public String toString() {
return name;
}
}
public class CarMapper {
public static void main(String[] args) {
List<Vehicle> list = new ArrayList<>();
list.add(new MotorCycle("Honda"));
list.add(new MotorCycle("Harley-Davidson"));
list.add(new Car("Ford"));
list.add(new Car("Chrysler"));
Map<Class<?>, List<Vehicle>> inventory = list.stream().collect(
Collectors.groupingBy(Object::getClass));
}
}
这是否合理取决于您(以及评论的其他人)。您可能仍需要地图才能从用户菜单中获得正确的 class。
Map<String, Class<?>> menuMap = new HashMap<>();
menuMap.put("Car", Car.class);
menuMap.put("MotorCycle", MotorCycle.class);
Class<?> lookup = menuMap.get("Car");
for (Vehicle v : inventory.get(lookup)) {
System.out.println(v.toString());
}