2012-08-24 72 views
0

我有延伸的豆几个对象:如何基于某个类实例化特定的实现?

public class Fruit {} 

public class Banana extends Fruit {} 

public class Pear extends Fruit {} 

然后我把不同的实现,每一个bean的接口。

public interface Milkshake { 
    public String doMilkshake(); 
} 

public class FruitMilkshake implements Milkshake { 
    public String doMilkshake() { 
     return "Fruit Milkshake!"; 
    } 
} 

public class BananaMilkshake implements Milkshake { 
    public String doMilkshake() { 
     return "Banana Milkshake!"; 
    } 
} 

public class PearMilkshake implements Milkshake { 
    public String doMilkshake() { 
     return "Pear Milkshake!"; 
    } 
} 

如何根据我的bean的具体类型实例化正确的实现?

现在我已经使用了typization和一个Map来“映射”正确的实现。 喜欢这个:

public void hungry(Fruit fruit) { 
    Map<String, String> obj2impl = new HashMap<String, String>(); 
    obj2impl.put("Fruit", "FruitMilkshake"); 
    obj2impl.put("Banana", "BananaMilkshake"); 
    obj2impl.put("Pear", "PearMilkshake"); 

    String name = fruit.getClass().getCanonicalName(); 
    String implName = obj2impl.get(name); 
    Milkshake milkshake = (Milkshake) Class.forName(implName).newInstance(); 

    milkshake.doMilkshake(fruit); 
} 



public interface Milkshake <T t> { 
    public String doMilkshake(T t); 
} 

public class FruitMilkshake implements Milkshake<Fruit> { 
    public String doMilkshake(Fruit fruit) { 
     return "Fruit Milkshake!"; 
    } 
} 

public class BananaMilkshake implements Milkshake<Banana> { 
    public String doMilkshake(Banana banana) { 
     return "Banana Milkshake!"; 
    } 
} 

public class PearMilkshake implements Milkshake<Pear> { 
    public String doMilkshake(Pear pear) { 
     return "Pear Milkshake!"; 
    } 
} 

更好的方法来实现这一目标?

+0

你不应该在每次饥饿调用时重新创建水果地图。改为将该地图作为实例变量。或者打开水果名称。 – maba

回答

1

更好的实现方法?

好起点是避免反思类的名称:

Map<String, Class<? extends Milkshake>> obj2impl = 
    new HashMap<String, Class<? extends Milkshake>>(); 
obj2impl.put("Fruit", FruitMilkshake.class); 
obj2impl.put("Banana", BananaMilkshake.class); 

... 

Milkshake milkshake = obj2impl.get(text).newInstance(); 

现在仍然需要你在每个实现参数的构造函数,它仍然总是将创建一个新的实例。如果使用Provider样的概念,就可以避开这个问题:

Map<String, Provider<Milkshake>> map = ...; 
// Fill the map with providers, some of which could create a new instance, 
// and some could reuse an existing one 

... 

Milkshake milkshake = map.get(text).get(); 

编辑:具有重读后,你可以摆脱文字部分的为好,并有Map<Class<?>, Provider<Milkshake>>。如果可能的话,避免硬编码类的名称。

当然,如果你的Fruit类有一个makeMilkshake抽象方法,那会更好......

+0

我显然不使用这个名字。这只是一个例子。 – Enrichman

+1

@Enrichman:我不是在暗示这些是真实姓名,而是在地图中使用类名的*文本*,而不是使用类文字。这是我的观点。 –

+0

好的,明白了。你是对的。 :)顺便说一句我在我的项目中使用Guice,所以提供者的东西将是有用的。 IoC是我认为的唯一方式。 – Enrichman

0
public class Fruit { 
    public Class<? extends Milkshake> getMilkshakeClass() { 
     return Milkshake.class; 
    } 
} 

public class Banana extends Fruit { 
    public Class<? extends Milkshake> getMilkshakeClass() { 
     return Banana.class; 
    } 
} 

public class Pear extends Fruit { 
    public Class<? extends Milkshake> getMilkshakeClass() { 
     return PearMilkshake.class; 
    } 
} 

你甚至可能想使具有上述作为一个抽象的方法的AbstractFruit类方法,他们必须重写

public abstract class AbstractFruit { 
    public abstract Class<? extends Milkshake> getMilkshakeClass(); 
} 

而不是让他们扩展水果,扩展它。

+0

现在,您正在捆绑“水果,香蕉和梨”,以了解有关“奶昔”的知识。他们为什么会有关于奶昔的知识? – maba

+0

因为你可以拿一个水果,并做一个奶昔呢?这是一个完全合理的想法。他没有说明他们对方有什么确切的知识,但他们都是公开的,所以我认为他们都知道对方 –

+0

你可以做一个鸡尾酒或果酱或任何... – maba

相关问题