2

我是编写 API 的新手,做了一些研究并意识到要完成我想要的事情,我需要使用依赖注入来完成它。我正在编写一个具有两个数据源的 android 应用程序。一种是通过 Web 服务公开,另一种是 SQLlite。SQLlite 在没有数据连接可用时用作备份(暂时只对 API 的 webservice 部分感兴趣会重构)。我想编写一个 API,为其提供一个抽象层,根据所需的模型调用正确的数据访问类。因此,我有一个描述 api 应实现的方法的接口,称为 IDataAccess(仅对 getAll 感兴趣,目的是弄清楚要做什么)。

public interface IDataAccess {  
    public <T> List <T> getAll ();  
    public <T> T getById (int id);
}//end  IDataAccess

我正在使用 Guice 进行依赖注入。guice 模块是:

public class Data extends AbstractModule {
    public void configure () {
        bind (IDataAccess.class).to(UserData.class);
    }
}

IDataAccess 的实现是(注意我使用的是 Jersey 客户端 API):

public class UserData extends DataAccessManager implements IDataAccess {    
    @SuppressWarnings("unchecked")
    public List <User> getAll () {
        WebResource webResource = client.resource (WebResourceURL.URL_USER_ALL);
        ClientResponse response = webResource.accept(MediaType.APPLICATION_JSON).get(ClientResponse.class);
        if (response.getStatus () == 200)
            return response.getEntity(new GenericType <List <User>> () {}) ;
        else
            return null;        
    }//end getAllUsers method
}

我有一个类可以加载和实例化所需的任何资源。它还返回一个名为 DataAccessFactory 的 DataManager 实例。

public class DataAccessFactory {
    private Client client;
    private static DataAccessFactory instance;
    private DataAccessFactory() {
        client = Client.create();
    }
    public static DataAccessFactory getInstance() {
        /*
         * check if instance  variable is instantiated.
         * if it is not then instantiated it and returns
         * created instance.
         */
        if (instance == null) {
            instance = new DataAccessFactory();
            return instance;
        } else
            return instance;
    }//end getInstance method
    public DataAccessManager createDataAccessManager() {
        return new DataAccessManager(client);
    }//end createDataAccessManager method
}

然后我有实际的 DataAccessManager 类:

public class DataAccessManager {
    protected Client client;
    protected DataAccessManager (Client client)n{
        this.client = client;
    }//end constructor 
    public <T>  List <Object> getAll(T t) {
        Data module = new Data ();
        Injector injector = Guice.createInjector(module);
        IDataAccess data = (IDataAccess) injector.getInstance(t.getClass());
        return (List<Object>) data;
    }//end fetchAllUser method
}

要在此类上调用用户模型,我会执行以下操作:

@Test
public void fetchUser () {
        DataAccessManager m = DataAccessFactory.getInstance().createDataAccessManager();
        List<User> user = (List<User>)  m.getAll(new Userdata ());
        if (user == null)
            assertEquals(1, 2);
        else
            assertEquals(1, 1);
}

理想情况下,我现在想要做的是,调用 UserData 来获取所有 User 对象或 OrderData(在编写实现时)类来获取所有订单对象等。

问题是这给出了一个错误:

无法从列表投射到列表

.我怎样才能解决这个问题或重组它以使其有意义?

4

2 回答 2

2

1) You are creating an injector (Guice.createInjector) per request. Injector creation is expensive and should normally be done during application loading. You should see DI as a bootstrap mechanism and keep it simple.

2) You don't need the DataAccessFactory. First there is no need for a factory as the createDataAccessManager instantiation does not require any logic and secondly Guice could also take care of the factory pattern.

I would personally keep it simple and inject with Guice directly the UserData instance into each service that needs it, without using the rather complicated Abstraction approach showed here. Still, it does not solve the problem of dealing with network issues. My guess is that each data access class will have to deal with connectivity in a specific way, so the logic should be directly here.

For the list casting problem, see http://docs.oracle.com/javase/tutorial/java/generics/subtyping.html

If you will continue that way, I would recommend to read about erasure also.

于 2012-10-18T16:15:05.730 回答
1

这是您经常遇到的问题。我们期望 as Stringis-a ObjectList<String>is-aList<Object>也是真的。但事实并非如此。这就是为什么此类演员不起作用的原因:

@Test
public void fetchUser () {
//...
List<User> user = (List<User>)  m.getAll(new Userdata ());
//..
}

我建议重写该DataAccessManager.getAll()方法以返回正确的列表。

DataAccessManager.getAll()作为记录,我在方法中发现了一个错字。我认为当你写return (List<Object>) data;的时候你宁愿写,return List<Object> data.getAll();否则你不能将 IDataAccess 转换为 List。

为了摆脱这种铸造地狱,我建议向IDataAccess接口及其实现添加一个类型:

public interface IDataAccess<T> {  
    public List <T> getAll ();  
    public T getById (int id);
}//end  IDataAccess

public class UserData extends DataAccessManager<User> implements IDataAccess<User> {
// your implementation
} 

我还要澄清 DataAccesManager 本身:

public class DataAccessManager<T> {
    //fields and constructors
    public List<T> getAll(IDataAccess<T> access) { //this is how the test suggests you want to use this method
        Data module = new Data ();
        Injector injector = Guice.createInjector(module);
        IDataAccess<T> data = (IDataAccess<T>) injector.getInstance(access.getClass()); //why is this line important? why don't you use the access parameter instead?
        return data.getAll();
    }
}
于 2012-10-18T16:33:13.367 回答