2017-05-05 76 views
1

我想要做的是实现一个点击流数据生成器,它可以很好地扩展。Java通用工厂模式实现

我在想:

的属性是类,例如每个用户都有某种浏览器。所以有一个浏览器类。相同的语言,插件等...

对于每个属性有一个工厂,创建一个属性的随机实例,例如新的浏览器(“Firefox”)或新的语言(“德语”)。可能的值存储在每个属性的文件中。

基本上所有这些工厂和财产类都在做同样的事情。现在,我为每个房产都有一个独立的工厂,每个新的房产都必须建立一个新工厂。

我的问题是,是否有可能对我拥有的所有房产和新房产实施某种通用工厂。

这是我的代码:

public abstract class Property { 

protected String value; 
Random rand; 

public Property(String value) { 
    this.rand = new Random(); 
    this.value = value; 
} 

@Override 
public String toString() {  
    return this.value; 
} 
} 


public class Browser extends Property{ 

public Browser(String value) { 
    super(value); 
} 
} 

public abstract class AbstractFactory implements IFactory{ 
List<String> valuesList; 
FileReader fileReader; 
BufferedReader bufferedReader; 
Random rand; 

public AbstractFactory(String inputFile) {  
    rand = new Random(); 
    this.valuesList = new LinkedList<String>();  
    String line = null; 

    try { 
     fileReader = new FileReader(inputFile); 
     bufferedReader = new BufferedReader(fileReader); 
     while ((line = bufferedReader.readLine()) != null) { 
      valuesList.add(line); 
     } 
     bufferedReader.close(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 

} 
} 


import model.Browser; 

public class BrowserFactory extends AbstractFactory{ 

public BrowserFactory(String inputFile) { 
    super(inputFile); 
} 

@Override 
public Browser getInstance() {  
    return new Browser(valuesList.get(rand.nextInt(valuesList.size()))); 
} 

} 
+1

你能证明你有试过吗? –

+0

你想要什么肯定是可能的,但我需要一些更多的信息来弄清楚你需要什么。你确定像Builder这样的东西可能不适合你吗? –

+0

我想要什么,顶部摆脱我拥有的所有工厂类(每个功能一个),都做同样的事情。 Thema之间的唯一区别是不同的输入路径和getinstance方法的不同输出类型。 – Joha

回答

0

匈牙利命名法(在技术上,系统匈牙利命名法)是令人难以接受的。 Java接口不应以I前缀命名。如果你看看Java SE documentation,你会发现没有一个以这种方式命名的单一接口。

因此,考虑到这一点,你将定义Factory为:

public interface Factory<T> { 
    T getInstance(); 
} 

然后AbstractFactory将复制:

public abstract class AbstractFactory<T> implements Factory<T> { 

最后,BrowserFactory可以简单地泛型类型更具体:

public class BrowserFactory extends AbstractFactory<Browser> { 
    @Override 
    public Browser getInstance() { 

如果你想做一个具体的类,你需要一些你均匀的创建类的方式。如果它们都具有采用String构造函数,你可以使用反射:

public class FeatureFactory<T> extends AbstractFactory<T> { 
    private final Constructor<T> constructor; 

    public FeatureFactory(Class<T> featureType) { 
     try { 
      this.constructor = featureType.getConstructor(String.class); 
     } catch (ReflectiveOperationException e) { 
      throw new IllegalArgumentException(
       "Cannot find/access (String) constructor in " + featureType, e); 
     } 
    } 

    @Override 
    public T getInstance() { 
     try { 
      return constructor.newInstance(
       valuesList.get(rand.nextInt(valuesList.size()))); 
     } catch (ReflectiveOperationException e) { 
      throw new RuntimeException(e); 
     } 
    } 
} 

你必须通过反思工作Class对象。泛型会在运行时被删除,所以您不能从<T>推导出类。实际上,你会发现Java SE类以相同的方式工作。例如参见EnumSetEnumMap

另有些更简洁的方法是使用Java 8 Function

public class FeatureFactory<T> extends AbstractFactory<T> { 
    private final Function<String, ? extends T> creator; 

    public FeatureFactory(Function<String, ? extends T> creator) { 
     this.creator = Objects.requireNonNull(creator, 
      "Creation function cannot be null"); 
    } 

    @Override 
    public T getInstance() { 
     creator.apply(
      valuesList.get(rand.nextInt(valuesList.size()))); 
    } 
} 

这可能与类似调用:

FeatureFactory<Browser> browserFactory = new FeatureFactory<>(Browser::new);