java中使用泛型的工厂方法模式,如何?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/855332/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Factory method pattern in java using generics, how to?
提问by Jay
I have code that looks like follows:
我有如下所示的代码:
public interface BaseDAO{
// marker interface
}
public interface CustomerDAO extends BaseDAO{
public void createCustomer();
public void deleteCustomer();
public Customer getCustomer(int id);
// etc
}
public abstract class DAOFactory {
public BaseDAO getCustomerDAO();
public static DAOFactory getInstance(){
if(system.getProperty("allowtest").equals("yes")) {
return new TestDAOFactory();
}
else return new ProdDAOFactory();
}
public class TestDAOFactory extends DAOFactory{
public BaseDAO getCustomerDAO() {
return new TestCustomerDAO(); // this is a concrete implementation
//that extends CustomerDAO
//and this implementation has dummy code on methods
}
public class ProdDAOFactory extends DAOFactory {
public BaseDAO getCustomerDAO() {
return new ProdCustomerDAO(); // this implementation would have
// code that would connect to the database and do some stuff..
}
}
Now, I do know that this code smells.. for many reasons. However, this code is here too: http://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html, refer 9.8
现在,我确实知道这段代码很臭……有很多原因。但是,此代码也在这里:http: //java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html,参考 9.8
What I intend to do is this: 1) Switch my DAOs implementations at runtime based on environment (system properties). 2) Make use of java generics so that I can avoid type casting... for instance does something like this:
我打算做的是:1)在运行时根据环境(系统属性)切换我的 DAO 实现。2)利用java泛型,这样我就可以避免类型转换......例如做这样的事情:
CustomerDAO dao = factory.getCustomerDAO();
dao.getCustomer();
As opposed to:
与之相反:
CustomerDAO dao = (CustomerDAO) factory.getCustomerDAO();
dao.getCustomer();
Your thoughts and suggestions, please.
请您提出您的想法和建议。
采纳答案by Mihai Toader
You should define the factory like that:
您应该像这样定义工厂:
public abstract class DAOFactory<DAO extends BaseDAO> {
public DAO getCustomerDAO();
public static <DAO extends BaseDAO> DAOFactory<DAO> getInstance(Class<DAO> typeToken){
// instantiate the the proper factory by using the typeToken.
if(system.getProperty("allowtest").equals("yes")) {
return new TestDAOFactory();
}
else return new ProdDAOFactory();
}
getInstance should return a proper typed DAOFactory.
getInstance 应该返回一个正确类型的 DAOFactory。
The factory variable will have the type:
工厂变量将具有以下类型:
DAOFactory<CustomerDAO> factory = DAOFactory<CustomerDAO>.getInstance(CustomerDAO.class);
and the usage will be properly typed:
并且将正确键入用法:
CustomerDAO dao = factory.getCustomerDAO();
dao.getCustomer();
the only problem will probably be a cast required inside the getInstance methods.
唯一的问题可能是 getInstance 方法中需要的强制转换。
回答by AlbertoPL
When I've used factories I've typically used instanceof to determine the true type of the object. For example:
当我使用工厂时,我通常使用 instanceof 来确定对象的真实类型。例如:
CustomerDAO dao;
if (factory.getCustomerDAO() instanceof CustomerDAO) {
dao = factory.getCustomerDAO();
}
dao.getCustomer();
This just seems cleaner to me, especially if factory.getCustomerDAO() doesn't return anything close to a CustomerDAO (due to changes in implementation).
这对我来说似乎更清晰,特别是如果 factory.getCustomerDAO() 没有返回任何接近 CustomerDAO 的东西(由于实现的变化)。
Just my two cents.
只有我的两分钱。
回答by javashlook
There's a bunch of articles detailing what you need:
有很多文章详细说明了您需要什么:
- Generic DAO Pattern With JDK 5.0
- Generic Data Access Objects(same as above)
- Don't repeat the DAO(with Spring, but the principles are the same)
- Java 1.5 Generic DAO(Spring again)
- 使用 JDK 5.0 的通用 DAO 模式
- 通用数据访问对象(同上)
- 不要重复DAO(用Spring,但原理是一样的)
- Java 1.5 通用 DAO(又是 Spring)
Please note that, unlike your example, there is no reason why the methods of DAOFactory
should not return the actual subclasses (i.e. CustomerDAO getCustomerDAO()
). Furthermore, main benefit of using generic DAOs is having the entity type "genericized", so you don't have to cast from load()/get()/find()
and similar methods.
请注意,与您的示例不同,没有理由DAOFactory
不应该返回实际的子类(即CustomerDAO getCustomerDAO()
)。此外,使用泛型 DAO 的主要好处是使实体类型“泛型化”,因此您不必从load()/get()/find()
类似的方法中进行转换。
回答by erickson
Your example doesn't demonstrate a need for BaseDAO
, and there is no reason why DAOFactory.getCustomerDAO()
shouldn't be declared to return a CustomerDAO
. So, I don't really see a need for generics there. However, consider the following:
您的示例没有证明需要BaseDAO
,并且没有理由DAOFactory.getCustomerDAO()
不应该声明返回 a CustomerDAO
。所以,我真的不认为那里需要泛型。但是,请考虑以下事项:
interface DataAccess<T> {
void store(T entity);
T lookup(Serialiable identifier);
void delete(Serializable identifier);
Collection<? extends T> find(Criteria query);
}
abstract class DataAccessFactory {
abstract DataAccess<T> getDataAccess(Class<T> clz);
static DataAccessFactory getInstance() {
...
}
}
I've used something like this approach in several projects, and it is very nice to write one DAO that works for every entity in the model. The weakness is the "finder" methods. There are some neat approaches, and upcoming work in JPA is standardizing a "Criteria" API, but for now it is often easiest to expose the underlying persistence mechanism's criteria.
我已经在几个项目中使用过类似这种方法的方法,编写一个适用于模型中每个实体的 DAO 非常好。弱点是“finder”方法。有一些巧妙的方法,JPA 即将开展的工作是标准化“标准”API,但目前通常最容易公开底层持久性机制的标准。