工厂模式结合泛型时参数化类原始使用问题及优化咨询
泛型与工厂模式结合的实践问题及解决方案
背景
我学习了Factory模式和泛型的用法,正尝试将二者结合使用。以下是我的实践内容:
无泛型输入参数 - 无警告
public abstract class ArtifactCreator { public abstract void setArtifacts(String workflowInput); }
public class FooArtifactCreator extends ArtifactCreator { @Override public void setArtifacts(String input) { return null; } }
public class BarArtifactCreator extends ArtifactCreator { @Override public void setArtifacts(String input) { return null; } }
public class Factory { public ArtifactCreator getArtifactCreator(String domain) { if (domain == "foo") { return new FooArtifactCreator(); } else if (domain == "bar") { return new BarArtifactCreator(); } return null; } }
核心问题
上述代码中workflowInput被限定为String类型,但我希望它能支持通用POJO类型。
使用泛型后的警告问题
引入泛型后,我在Factory.java和Store.java中收到以下警告,希望通过正确使用泛型消除这些警告:
Raw use of parameterized class 'ArtifactCreator':出现在Store.java和Factory.java中Unchecked call to 'setArtifacts(T)' as a member of raw type 'ArtifactCreator':出现在Store.java中
泛型版本的核心代码如下:
泛型版ArtifactCreator
public abstract class ArtifactCreator<T> { public abstract void setArtifacts(T workflowInput); }
具体实现类
public class FooArtifactCreator extends ArtifactCreator<FooInput> { @Override public void setArtifacts(FooInput input) { return null; } }
public class BarArtifactCreator extends ArtifactCreator<BarInput> { @Override public void setArtifacts(BarInput input) { return null; } }
工厂类(未修正)
public class Factory { public ArtifactCreator getArtifactCreator(String domain) { if (domain == "foo") { return new FooArtifactCreator(); } else if (domain == "bar") { return new BarArtifactCreator(); } return null; } }
输入类与Store类
public class Input { private String domain; private String otherInput; // getter方法省略 }
public class Store { private final Factory factory; public Store(Factory factory) { this.factory = factory; } public ArtifactCreator getCaseClosureArtifactFactory(Input req) { ArtifactCreator artifactCreator = factory.getArtifactCreator(req.getDomain()); // 实际场景中 - 根据`Input` POJO中的`otherInput`字段创建FooInput或BarInput FooInput input = new FooInput(); artifactCreator.setArtifacts(input); return artifactCreator; } }
我想到的替代方案(存在缺陷)
我尝试过创建一个包含所有具体输入类型的WorkflowInput,但这种方法会存在多余的空字段,不够优雅:
public class WorkflowInput { private FooInput fooInput; private BarInput barInput; // getter/setter方法省略 } public abstract class ArtifactCreator { public abstract void setArtifacts(WorkflowInput workflowInput); } public class FooArtifactCreator extends ArtifactCreator { @Override public void setArtifacts(WorkflowInput input) { FooInput fooInput = input.getFooInput(); // 提取特定输入 } } public class BarArtifactCreator extends ArtifactCreator { @Override public void setArtifacts(WorkflowInput input) { BarInput barInput = input.getBarInput(); // 提取特定输入 } }
正确的泛型解决方案
以下是无需冗余字段、能消除所有警告的合理方案:
1. 修正泛型类与工厂类
首先确保ArtifactCreator是正确的泛型类,同时修改工厂类返回带通配符的泛型类型,避免原始类型:
public abstract class ArtifactCreator<T> { public abstract void setArtifacts(T workflowInput); } public class Factory { public ArtifactCreator<?> getArtifactCreator(String domain) { // 注意:字符串比较改用equals,避免引用比较问题 if ("foo".equals(domain)) { return new FooArtifactCreator(); } else if ("bar".equals(domain)) { return new BarArtifactCreator(); } return null; } }
2. 新增输入工厂类
创建一个输入工厂,根据Input生成对应的具体输入类型,保证类型与domain匹配:
public class InputFactory { public static Object createSpecificInput(Input req) { if ("foo".equals(req.getDomain())) { FooInput fooInput = new FooInput(); // 根据req.otherInput初始化fooInput的字段 return fooInput; } else if ("bar".equals(req.getDomain())) { BarInput barInput = new BarInput(); // 根据req.otherInput初始化barInput的字段 return barInput; } return null; } }
3. 修正Store类,使用泛型捕获保证类型安全
通过泛型捕获方法,安全调用setArtifacts,消除unchecked警告:
public class Store { private final Factory factory; public Store(Factory factory) { this.factory = factory; } public ArtifactCreator<?> getCaseClosureArtifactFactory(Input req) { ArtifactCreator<?> artifactCreator = factory.getArtifactCreator(req.getDomain()); Object specificInput = InputFactory.createSpecificInput(req); // 安全调用setArtifacts setArtifactsSafely(artifactCreator, specificInput); return artifactCreator; } @SuppressWarnings("unchecked") private <T> void setArtifactsSafely(ArtifactCreator<T> creator, T input) { creator.setArtifacts(input); } }
方案说明
- 该方案通过泛型捕获机制,确保
ArtifactCreator和输入类型的匹配性,因为InputFactory与Factory使用同一个domain生成对应实例,类型一致性有保障,因此@SuppressWarnings("unchecked")的使用是安全的。 - 无需创建包含所有输入类型的冗余类,保持代码的简洁性和扩展性,新增输入类型时只需扩展
InputFactory和对应的ArtifactCreator实现即可。
内容的提问来源于stack exchange,提问作者ababuji
相关产品推荐
相关产品推荐

