2

私はAPIを作成するのが初めてで、いくつかの調査を行い、依存性注入を使用してそれを実行するために必要なことを達成するために気づきました。私は2つのデータソースを持つAndroidアプリケーションを書いています。1つはWebサービスによって公開され、もう1つはSQLliteです。SQLliteは、データ接続が利用できない場合のバックアップとして使用されます(当面は、APIのWebサービス部分にのみ関心があります)。必要なモデルに基づいて適切なデータアクセスクラスを呼び出す、これに抽象化レイヤーを提供するAPIを作成したいと思います。したがって、IDataAccessと呼ばれるAPIが実装する必要のあるメソッドを記述するインターフェイスがあります(何をすべきかを理解する目的で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 Client 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

Guice.createInjector1)リクエストごとにインジェクター()を作成しています。インジェクターの作成には費用がかかるため、通常はアプリケーションの読み込み中に行う必要があります。DIをブートストラップメカニズムと見なし、シンプルに保つ必要があります。

2)DataAccessFactoryは必要ありません。createDataAccessManagerのインスタンス化にはロジックが必要ないため、最初にファクトリは必要ありません。次に、Guiceがファクトリパターンを処理することもできます。

UserData個人的にはシンプルに保ち、ここに示すかなり複雑な抽象化アプローチを使用せずに、Guiceを使用してインスタンスを必要とする各サービスに直接注入します。それでも、ネットワークの問題に対処する問題は解決されません。私の推測では、各データアクセスクラスは特定の方法で接続を処理する必要があるため、ロジックはここに直接配置する必要があります。

リストのキャストの問題については、http://docs.oracle.com/javase/tutorial/java/generics/subtyping.htmlを参照してください

そのように続けるのであれば、消去についても読むことをお勧めします。

于 2012-10-18T16:15:05.730 に答える
1

それはあなたが陥る一般的な問題です。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をリストにキャストすることはできません。

このキャストの地獄から逃れるために、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 に答える