我正在设计一个虚拟水族馆.我有一个类:我继承的鱼,以创建不同物种的类.用户可以在组合框中选择物种,然后单击按钮将鱼放入罐中.我使用以下代码创建鱼:
switch(s){
case "Keegan" :
stock.add(new Keegan(this, x,y));
break;
case "GoldenBarb" :
stock.add(new GoldenBarb(this, x,y));
Run Code Online (Sandbox Code Playgroud)
"stock"是LinkedList,"s"是在Jcombobox中选择的String.当我添加一堆不同的物种时,我将不得不创建一个长开关.我希望代码看起来像:
stock.add(new s(this,x,y));
Run Code Online (Sandbox Code Playgroud)
并且省去了开关,这样我所要做的就是创建类并将其名称添加到组合框并让它工作.有办法吗?任何帮助表示赞赏.
您想要使用一堆工厂对象,存储在Map您在其中使用的字符串键下switch.
这些是您应该拥有的各种鱼类.
abstract class FishBase {}
class Keegan extends FishBase {
Keegan(Object _this, int x, int y) {
// ...
}
}
class GoldenBarb extends FishBase {
GoldenBarb(Object _this, int x, int y) {
// ...
}
}
Run Code Online (Sandbox Code Playgroud)
所有鱼类工厂的界面.鱼类工厂代表了一种创造某种鱼类的方法.你没有提到构造函数签名是什么,所以我选择了一些类型.
interface IFishFactory {
FishBase newFish(Object _this, int x, int y);
}
Run Code Online (Sandbox Code Playgroud)
为每种鱼类设置一个工厂.这些显然不需要是匿名类,我用它们来减少混乱.
Map<String, IFishFactory> fishFactories = new HashMap<>();
fishFactories.put("Keegan", new IFishFactory() {
public FishBase newFish(Object _this, int x, int y) {
return new Keegan(_this, x, y);
}
});
fishFactories.put("GoldenBarb", new IFishFactory() {
public FishBase newFish(Object _this, int x, int y) {
return new GoldenBarb(_this, x, y);
}
});
Run Code Online (Sandbox Code Playgroud)
然后从Map使用已有的字符串中选择工厂.您可能想要检查是否存在给定名称的工厂.
stock.add(fishFactories.get(s).newFish(this, x, y));
Run Code Online (Sandbox Code Playgroud)
现在,如果所有的fish类都具有完全相同的构造函数签名,则可以创建一个可以使用反射处理所有类的工厂类,并删除一些样板.
class ReflectionFishFactory implements IFishFactory {
Constructor<? extends FishBase> fishCtor;
public ReflectionFishFactory(Class<? extends FishBase> fishClass)
throws NoSuchMethodException {
// Find the constructor with the parameters (Object, int, int)
fishCtor = fishClass.getConstructor(Object.class,
Integer.TYPE,
Integer.TYPE);
}
@Override
public FishBase newFish(Object _this, int x, int y) {
try {
return fishCtor.newInstance(_this, x, y);
} catch (InstantiationException
| InvocationTargetException
| IllegalAccessException e) {
// this is terrible error handling
throw new RuntimeException(e);
}
}
}
Run Code Online (Sandbox Code Playgroud)
然后为每个适用的子类注册它.
for (Class<? extends FishBase> fishClass :
Arrays.asList(Keegan.class,GoldenBarb.class)) {
fishFactories.put(fishClass.getSimpleName(),
new ReflectionFishFactory(fishClass));
}
Run Code Online (Sandbox Code Playgroud)
我认为反思可能就是你在寻找的东西.这允许您避免使用switch语句,这就是您所要求的.
反射(除其他外)允许您只使用字符串运行方法.所以在Java中,你通常会调用这样的方法:
new Foo().hello();
Run Code Online (Sandbox Code Playgroud)
使用Reflection,您可以使用字符串来调用方法,如下所示:
Class<?> clazz = Class.forName("Foo");
clazz.getMethod("hello").invoke(clazz.newInstance());
Run Code Online (Sandbox Code Playgroud)
关于工厂模式(现在参考其他答案),据我所知,这只是封装switch语句(或您选择使用的任何方法).Factory模式本身不是避免switch语句的一种方法.工厂模式是一件好事,但不是你问的问题.(在任何情况下,您可能都希望使用工厂模式).
让我们一步一步看看你想走多远.
首先,您可以在FishFactory中抽象出鱼的创建,这样您执行switch语句的原始位置可以简单地更改为
stock.add(fishFactory.createFish(s, x, y));
Run Code Online (Sandbox Code Playgroud)
然后开关盒进入工厂:
public class SimpleFishFactory {
@Override
public Fish createFish(String fishType, int x, int y) {
switch(s){
case "Keegan" :
return new Keegan(this, x,y);
break;
case "GoldenBarb" :
return new GoldenBarb(this, x,y);
//....
}
}
}
Run Code Online (Sandbox Code Playgroud)
(我假设你的所有鱼都有与Fish相同的界面/基类)
如果您想让创作看起来更优雅,有两种常用的方法可供选择:
反思
想法很简单.首先设置字符串与鱼类(或构造函数)的查找表,每个createFish()都通过反射创建鱼的新实例
public class ReflectionFishFactory {
private Map<String, Class<? extends Fish>> fishClasses = new HashMap<...>();
public ReflectionFishFactory() {
//set up fishClasses with name vs corresponding classes.
// you may read it from file, or hard coded or whatever
fishClasses.put("Keegan", Keegan.class);
fishClasses.put("GoldenBarb", GoldenBarb.class);
}
@Override
public Fish createFish(String fishType, int x, int y) {
Class<?> fishClass = fishClasses.get(fishType);
// use reflection to create new instance of fish by
// by using fishClass
}
}
Run Code Online (Sandbox Code Playgroud)
原型模式 由于某些原因,您可能不想使用反射(可能由于反射的缓慢,或者不同的鱼有非常不同的创建方式),您可以查看GoF的原型模式.
public class PrototypeFishFactory {
private Map<String, Fish> fishes = new HashMap<...>();
public ReflectionFishFactory() {
//set up fishClasses with name vs corresponding classes.
// you may read it from file, or hard coded or whatever
fishClasses.put("Keegan", new Keegan(....) );
fishClasses.put("GoldenBarb", new GoldenBarb(....) );
}
@Override
public Fish createFish(String fishType, int x, int y) {
return fishes.get(fishType).cloneNewInstance(x, y);
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
448 次 |
| 最近记录: |