3

静的メソッドで一般的な型を使用する際に問題が発生しました。

ソース コードに関するすべてのコメント、特にコードを大幅に改善するコメントを歓迎します。また、現在のところ、JDBC 以外の外部フレームワークを使用する予定はありません。シンプルに保つためです。あまり強調しないでください。

外部フレームワークを使用しないという私の見解は、データベースで使用する操作が非常に最小限であるという事実によっても裏付けられています。

  • データの挿入
  • データの更新
  • すべてのフィールドを取得しています。(そして、別の SQL クエリを入力するだけで、取得するフィールドを選択することができます。

完全なフレームワークを作成するつもりはないので、すべてをサポートするわけではないことは承知しています。すべてのフィールドを取得する速度は実際の問題ではありません。これはほとんどサーバーの起動時にのみ行われ、それ以外のときに使用される場合はバックグラウンド タスクで行われるため、いつ終了するかはあまり気にしません。 .

エンティティ.java:

abstract public class Entity<KeyType, DataType> {
    protected KeyType key;
    protected List<Object> data;

    public Entity() {
        data = new ArrayList<>();
    }

    //abstract public static Map<KeyType, DataType> getAll();

    protected List<Object> createData(final DataAction dataAction) {
        List<Object> list = new ArrayList<>();
        if (dataAction == DataAction.INSERT) {
            list.add(key);
        }

        list.addAll(data);

        if (dataAction == DataAction.UPDATE) {
            list.add(key);
        }
        return list;
    }

    abstract public void insert();

    abstract public void update();

    protected static <KeyType, DataType> Map<KeyType, DataType> getData(final Class<DataType> dataTypeClass, final String query) {
        Map<KeyType, DataType> map = new HashMap<>();
        try {
            PreparedStatement preparedStatement = DatabaseConnection.getConnection().prepareStatement(query);
            ResultSet resultSet = preparedStatement.executeQuery();
            while (resultSet.next()) {
                KeyType key = (KeyType)resultSet.getObject(1);
                int index = 2;
                List<Object> dataList = new ArrayList<>();
                while (resultSet.getObject(index) != null) {
                    dataList.add(resultSet.getObject(index));
                    index++;
                }
                DataType dataObject = null;
                try {
                    dataObject = dataTypeClass.getConstructor(List.class).newInstance(dataList);
                } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException ex) {
                    Logger.getLogger(Entity.class.getName()).log(Level.SEVERE, null, ex);
                }
                map.put(key, dataObject);
            }
        } catch (SQLException ex) {
            Logger.getLogger(Entity.class.getName()).log(Level.SEVERE, null, ex);
        }        
        return map;
    }

    protected void executeQuery(final String query, final List<Object> data) {
        try {
            PreparedStatement preparedStatement = DatabaseConnection.getConnection().prepareStatement(query);
            int dataIndex = 0;
            for (Object dataObject : data) {
                preparedStatement.setObject(dataIndex, dataObject);
                dataIndex++;
            }
            preparedStatement.execute();
            preparedStatement.close();
        } catch (SQLException ex) {
            Logger.getLogger(Entity.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

具体的な実装、Account.java:

public class Account extends Entity<String, Account> {
    private final static String SELECT_ALL_QUERY = "SELECT * FROM accounts";
    private final static String INSERT_QUERY = "INSERT INTO accounts (username, password) VALUES(?, ?)";
    private final static String UPDATE_QUERY = "UPDATE accounts SET password=? WHERE username=?";

    private String username;
    private String password;

    public Account(final String username, final String password) {
        this.username = username;
        this.password = password;

        key = username;
        data.add(password);
    }

    public Account(final List<Object> data) {
        this((String)data.get(0), (String)data.get(1));
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(final String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(final String password) {
        this.password = password;
    }

    public static Map<String, Account> selectAll() {
        return getData(Account.class, SELECT_ALL_QUERY);
    }

    @Override
    public void insert() {
        executeQuery(INSERT_QUERY, createData(DataAction.INSERT));
    }

    @Override
    public void update() {
        executeQuery(UPDATE_QUERY, createData(DataAction.UPDATE));
    }
}

私は一般的に具体的な実装に満足しています.それを最小限に抑えるpublic Account(final List<Object> data)ことができたようです.

ただ、やはりgetData()フロムEntityはどうしてもイマイチで、出来れば改善して欲しいところです。

私が使いたいのはのようなものですがDataType dataObject = new DataType(dataList)、ジェネリック型引数はインスタンス化できないようです。

現在のビューで現在のコードを最適化する方法はありますか? 具象クラスと抽象クラスをさらに分離することは可能ですか?

編集:

関連する質問を追加しました(このことについて完全に新しい質問をする必要はないと思いますよね?):

静的文字列 (SQL クエリ) と Account クラスから Entity クラスに移動する方法はありますinsert()update()?

4

2 に答える 2

0

Darwind と Nick Holt が言ったように、通常の状況では、オブジェクト リレーショナル マッピングの Java 標準仕様であるJPAを使用する必要があります。HibernateEclipseLink、または背後にある他のフレームワークを使用できます。それらの設計は、接続、トランザクションを管理できます。さらに、風変わりなフレームワークではなく標準を使用するということは、コミュニティの助けをより簡単に得ることができるということです。もう 1 つのオプションは、Spring JDBC を使用することです。これは非常に軽量で、多くのことを容易にします。

とにかく、学習目的でこれを行ったと思いますので、さらに先に進みましょう。

まず、担当するクラスやデータを取得するクラス (マネージャーまたはデータ アクセス オブジェクト ( DAO ) と呼びます) と、データ自体を表すエンティティを分離する必要があると思います。

私にとっては、クラスを使用してすべてのデータを取得すること自体は問題ではありません。問題は、キーの位置がハードコーディングされていることです。これはジェネリックを直接決定するべきではありません (すべての Entity 実装で同じことを意味します)。select * from...これにより、最初のフィールドがキーではない場合 (aは常に最初の位置でキーを返すと確信していますか?)、または複合キーを使用する場合、クエリはバグの対象になります。Mapperより良い解決策は、インターフェイスを作成し、エンティティごとに実装することだと思います。

public interface RecordMapper<KeyType, DataType extends Entity> {
    public void appendToMap(ResultSet resultSet, Map<KeyType, DataType>) throws SQLException;
}

マッパーの実装は、エンティティのインスタンス化、結果セットからのキーの取得、エンティティへの入力、期待するマップへの配置を担当する必要があります。

public class AccountMapper implement RecordMapper<String, Account>{
    public void appendToMap(ResultSet resultSet, Map<String, Account> accounts) throws SQLException {
        String user= resultSet.getString("userName");
        String pwd= resultSet.getString("passWord");
        Account account = new Account(user, pwd);
        accounts.put(user, account);
    }
}

先ほど言ったように、データ アクセス メソッドを DAO に移動する必要があります。 public class DAO{

    public <KeyType, DataType> Map<KeyType, DataType> getData(final RecordMapper<KeyType, DataType> mapper, final String query) {
        Map<KeyType, DataType> map = new HashMap<>();
        try {
            PreparedStatement preparedStatement = DatabaseConnection.getConnection().prepareStatement(query);
            ResultSet resultSet = preparedStatement.executeQuery();
            while (resultSet.next()) {
                mapper.appendToMap(resultSet, map);
            }
        } catch (SQLException ex) {
            Logger.getLogger(Entity.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            if(resultSet != null){
                try{resultSet.close();} catch (Exception e){}
            }
            if(preparedStatement!= null){
                try{preparedStatement.close();} catch (Exception e){}
            }
        }
        return map;
    }


    public void executeQuery(final String query, final List<Object> data) {
        try {
            PreparedStatement preparedStatement = DatabaseConnection.getConnection().prepareStatement(query);
            int dataIndex = 0;
            for (Object dataObject : data) {
                preparedStatement.setObject(dataIndex, dataObject);
                dataIndex++;
            }
            preparedStatement.execute();
        } catch (SQLException ex) {
            Logger.getLogger(Entity.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            if(resultSet != null){
                try{resultSet.close();} catch (Exception e){}
            }
            if(preparedStatement!= null){
                try{preparedStatement.close();} catch (Exception e){}
            }
        }
    }
}

2番目の質問に答えるために、リクエスト文字列を抽象的な親に入れるのではなく、確かに良い考えではないと思います。新しいエンティティを作成するたびに、親で新しいクエリを作成する必要があります。奇妙な...私があなたの質問を正しく理解していない限り。

個人的には、クエリは動的に構築する必要があり、リフレクション注釈を使用する必要があると思いますが、答えは少し長くなるはずです。繰り返しますが、JPA を見て、エンティティーの作成がどのように見えるべきかを確認できます。ところで、エンティティが親の Entity クラスを拡張する必要がなければ、さらに良いはずです。

于 2013-05-14T17:46:23.637 に答える