如果我们采用一个非常基本的例子:
public static void main(String[] args) {
animalMineralOrVegetable(new Animal());
animalMineralOrVegetable(new Mineral());
animalMineralOrVegetable(new Vegetable());
}
public static void animalMineralOrVegetable(Animal animal) {
print("Animal");
}
public static void animalMineralOrVegetable(Mineral mineral) {
print("Mineral");
}
public static void animalMineralOrVegetable(Vegetable vegetable) {
print("Vegetable");
}
由于在编译时已知所有类型,我们得到预期的结果。
但是,如果我们依赖另一个类的方法(例如,具有Object
返回类型),正在使用instanceof
并使用我们唯一的选项(反射除外)?
public static void main(String[] args) {
animalMineralOrVegetable(SomeClass.getSubject()); // object return type
}
如果声明的返回类型与其中一个方法实现不匹配(如上所述),上面显然不会编译。
显然,如果方法只返回每个类型实现的接口,我们将重构为单个animalMineralOrVegetable()
方法并调用常见的print方法。
我正在努力避免重复代码,但受到编写糟糕的旧API的限制。
答案 0 :(得分:1)
你提供了一个非常基本的例子,但我可能会尝试这样做:
public AnimalOrMineralWrapper{
String message;
T t;
public AnimalOrMineralWrapper(T t, String message){
this.t = t;
this.message = message;
}
public String getMessage(){
return message;
}
}
您现在可以使用包装类,如下所示:
public static void main(String[] args){
Mineral mineral = new Mineral();
AnimalOrMineralWrapper<Mineral> mineral = new AnimalOrMineralWrapper(mineral, "mineral");
}
public static void animalMineralOrVegetable(AnimalOrMineralWrapper wrapper) {
print(wrapper.getMessage());
}
如果print是一个API调用,你不能只传递任何东西,你可以添加一个额外的实例变量,或者只是在对象实例化时将message
设置为null。然后,如果message
为空,则不要进行服务调用。
这是一个潜在的解决方案,但我猜你的实现会更复杂。
答案 1 :(得分:0)
我在完全理解这个问题时遇到了一些麻烦。将对象类型作为参数传递给animalMineralOrVegetable()
方法会不会有问题?
据推测,你有某种抽象的父类Animal()
,Mineral()
和Vegetable()
都延伸,我们称之为Food()
public static void main(String[] args)
{
Animal animal = new Food();
Mineral mineral = new Food();
Vegetable vegetable = new Food();
animalMineralOrVegetable(animal, Animal.class);
animalMineralOrVegetable(mineral , Mineral.class);
animalMineralOrVegetable(vegetable , Vegetable.class);
}
public static void animalMineralOrVegetable(Food foodObject, Class clazz)
{
if(clazz == Mineral.class)
{
// logic
{
else if(clazz == Animal.class)
{
// logic
}
else if(clazz == Vegetable.class)
{
// logic
}
else
{
throw new Exception("Class not recognized.");
}
}
编辑:要处理未知类型,请instanceof
(如您在问题中提到的那样)。在我看来,这似乎非常简单。几个月后回到代码时很容易理解。
public static void animalMineralOrVegetable(Object foodObject)
{
if(foodObject instanceof Mineral.class)
{
print((Mineral) foodObject.getSubject());
{
else if(foodObject instanceof Animal.class)
{
print((Animal) foodObject.getSubject());
}
else if(foodObject instanceof Vegetable.class)
{
print((Vegetable) foodObject.getSubject());
}
else
{
throw new Exception("Passed object type cannot be determined.");
}
}
答案 2 :(得分:0)
这看起来像Visitor pattern有用的另一个例子。我假设你的所有类都有一些常见的超类型,或者至少你可以轻松添加一个。所以代码看起来像这样:
interface Visitor
{
void visitAnimal(Animal animal);
void visitMineral(Mineral mineral);
void visitVegetable(Vegetable vegetable);
}
abstract class BaseObject
{
public abstract void visit(Visitor visitor);
}
class Animal extends BaseObject
{
public String getUniqueAnimalString()
{
return "Animal";
}
@Override
public void visit(Visitor visitor)
{
visitor.visitAnimal(this);
}
}
class Mineral extends BaseObject
{
public String getUniqueMineralString()
{
return "Mineral";
}
@Override
public void visit(Visitor visitor)
{
visitor.visitMineral(this);
}
}
class Vegetable extends BaseObject
{
public String getUniqueVegetableString()
{
return "Vegetable";
}
@Override
public void visit(Visitor visitor)
{
visitor.visitVegetable(this);
}
}
然后你可以像这样使用它:
public static void main(String[] args)
{
List<BaseObject> objects = new ArrayList<>();
objects.add(new Animal());
objects.add(new Vegetable());
objects.add(new Mineral());
Visitor visitor = new Visitor()
{
@Override
public void visitAnimal(Animal animal)
{
System.out.println(animal.getUniqueAnimalString());
}
@Override
public void visitMineral(Mineral mineral)
{
System.out.println(mineral.getUniqueMineralString());
}
@Override
public void visitVegetable(Vegetable vegetable)
{
System.out.println(vegetable.getUniqueVegetableString());
}
};
for (BaseObject o : objects)
{
o.visit(visitor);
}
}
产生输出
动物
蔬菜
矿物