Javaにおけるシリアライズドエンティティパターン:データの永続化と交換の効率化
別名
- オブジェクトのシリアライゼーション
シリアライズドエンティティデザインパターンの目的
Javaのシリアライズドエンティティパターンは、オブジェクトのシリアライゼーションによりデータの転送と保存を簡素化します。 Javaオブジェクトをシリアライズされた形式に、またはシリアライズされた形式から簡単に変換できるため、効率的に保存および転送できます。
実際の例を用いたシリアライズドエンティティパターンの詳細な説明
実世界の例
シリアライズドエンティティデザインパターンの実世界の例としては、ビデオゲームでのゲーム状態の保存と読み込みプロセスが挙げられます。 プレイヤーが進行状況を保存することを決定すると、プレイヤーの位置、インベントリ、実績など、ゲームの現在の状態がJSONやバイナリなどのファイル形式にシリアライズされます。 このファイルは、プレイヤーのデバイスまたはクラウドサーバーに保存できます。 プレイヤーがゲームを再開したい場合は、シリアライズされたデータがゲームのオブジェクトにデシリアライズされ、プレイヤーは中断したところから続行できます。 このメカニズムにより、複雑なゲーム状態を簡単に保存および復元できるため、シームレスなゲーム体験が提供されます。
簡単な言葉で
シリアライズドエンティティデザインパターンは、Javaオブジェクトをシリアライズされた形式に、またはシリアライズされた形式から変換して、簡単に保存および転送できるようにします。
Wikipediaによると
コンピューティングでは、シリアライゼーションとは、データ構造またはオブジェクトの状態を、保存(例:二次記憶装置のファイル、一次記憶装置のデータバッファ)または送信(例:コンピュータネットワーク上のデータストリーム)できる形式に変換し、後で(場合によっては異なるコンピュータ環境で)再構築するプロセスです。 結果として得られる一連のビットがシリアライゼーション形式に従って再読み込みされると、元のオブジェクトと意味的に同一のクローンを作成するために使用できます。 参照を extensively 使用するなど、多くの複雑なオブジェクトの場合、このプロセスは簡単ではありません。 オブジェクトのシリアライゼーションには、以前にリンクされていた関連メソッドは含まれません。
Javaにおけるシリアライズドエンティティパターンのプログラム例
シリアライズドエンティティデザインパターンは、Javaオブジェクトをデータベースに簡単に永続化する方法です。 これは、`Serializable`インターフェースとDAO(データアクセスオブジェクト)パターンを使用します。 このパターンは、最初に`Serializable`を使用してJavaオブジェクトをバイトのセットに変換し、次にDAOパターンを使用してこのバイトのセットをBLOB(Binary Large OBject)としてデータベースに保存します。
まず、`Country`クラスがあります。これは、シリアライズされてデータベースに保存されるデータを表す単純なPOJO(Plain Old Java Object)です。 Java `Serializable`インターフェースを実装することは、シリアライズドエンティティデザインパターンにおいて非常に重要です。これは、オブジェクトをバイトストリームに変換し、それから復元できることを意味します。
@Getter
@Setter
@EqualsAndHashCode
@ToString
@AllArgsConstructor
public class Country implements Serializable {
private int code;
private String name;
private String continents;
private String language;
@Serial
private static final long serialVersionUID = 7149851;
}
次に、`CountryDao`インターフェースがあります。これは、データベースへの`Country`オブジェクトの永続化と取得のためのメソッドを定義します。
public interface CountryDao {
int insertCountry() throws IOException;
int selectCountry() throws IOException, ClassNotFoundException;
}
`CountrySchemaSql`クラスは、`CountryDao`インターフェースを実装します。 データベースに接続するために`DataSource`を使用し、シリアライズしてデータベースに保存する`Country`オブジェクトを使用します。
@Slf4j
public class CountrySchemaSql implements CountryDao {
public static final String CREATE_SCHEMA_SQL = "CREATE TABLE IF NOT EXISTS WORLD (ID INT PRIMARY KEY, COUNTRY BLOB)";
public static final String DELETE_SCHEMA_SQL = "DROP TABLE WORLD IF EXISTS";
private Country country;
private DataSource dataSource;
public CountrySchemaSql(Country country, DataSource dataSource) {
this.country = new Country(
country.getCode(),
country.getName(),
country.getContinents(),
country.getLanguage()
);
this.dataSource = dataSource;
}
@Override
public int insertCountry() throws IOException {
var sql = "INSERT INTO WORLD (ID, COUNTRY) VALUES (?, ?)";
try (var connection = dataSource.getConnection();
var preparedStatement = connection.prepareStatement(sql);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oss = new ObjectOutputStream(baos)) {
oss.writeObject(country);
oss.flush();
preparedStatement.setInt(1, country.getCode());
preparedStatement.setBlob(2, new ByteArrayInputStream(baos.toByteArray()));
preparedStatement.execute();
return country.getCode();
} catch (SQLException e) {
LOGGER.info("Exception thrown " + e.getMessage());
}
return -1;
}
@Override
public int selectCountry() throws IOException, ClassNotFoundException {
var sql = "SELECT ID, COUNTRY FROM WORLD WHERE ID = ?";
try (var connection = dataSource.getConnection();
var preparedStatement = connection.prepareStatement(sql)) {
preparedStatement.setInt(1, country.getCode());
try (ResultSet rs = preparedStatement.executeQuery()) {
if (rs.next()) {
Blob countryBlob = rs.getBlob("country");
ByteArrayInputStream baos = new ByteArrayInputStream(countryBlob.getBytes(1, (int) countryBlob.length()));
ObjectInputStream ois = new ObjectInputStream(baos);
country = (Country) ois.readObject();
LOGGER.info("Country: " + country);
}
return rs.getInt("id");
}
} catch (SQLException e) {
LOGGER.info("Exception thrown " + e.getMessage());
}
return -1;
}
}
最後に、`App`クラスで、`Country`オブジェクトと`CountrySchemaSql`オブジェクトを作成します。 次に、`insertCountry`メソッドを呼び出して`Country`オブジェクトをシリアライズし、データベースに保存します。 また、`selectCountry`メソッドを呼び出して、シリアライズされた`Country`オブジェクトをデータベースから取得し、`Country`オブジェクトにデシリアライズします。
public static void main(String[] args) throws IOException, ClassNotFoundException {
final var dataSource = createDataSource();
deleteSchema(dataSource);
createSchema(dataSource);
final var China = new Country(86, "China", "Asia", "Chinese");
final var UnitedArabEmirates = new Country(971, "United Arab Emirates", "Asia", "Arabic");
final var serializedChina = new CountrySchemaSql(China, dataSource);
final var serializedUnitedArabEmirates = new CountrySchemaSql(UnitedArabEmirates, dataSource);
serializedChina.insertCountry();
serializedUnitedArabEmirates.insertCountry();
serializedChina.selectCountry();
serializedUnitedArabEmirates.selectCountry();
}
コンソール出力
11:55:32.842 [main] INFO com.iluwatar.serializedentity.CountrySchemaSql -- Country: Country(code=86, name=China, continents=Asia, language=Chinese)
11:55:32.870 [main] INFO com.iluwatar.serializedentity.CountrySchemaSql -- Country: Country(code=971, name=United Arab Emirates, continents=Asia, language=Arabic)
これは、シリアライズドエンティティデザインパターンの基本的な例です。 Javaオブジェクトをシリアライズし、データベースに保存し、それらを取得してデシリアライズする方法を示しています。
Javaでシリアライズドエンティティパターンを使用する場合
- このパターンは、Java環境のさまざまな状態でデータの永続化が必要なアプリケーションに特に役立ちます。
- オブジェクトをネットワーク経由で共有したり、ファイルに保存したりする必要があるシナリオで役立ちます。
Javaにおけるシリアライズドエンティティパターンの実際のアプリケーション
- `Serializable`インターフェースを使用したJavaの組み込みシリアライゼーションメカニズム。
- Webアプリケーションでのセッションデータの保存。
- パフォーマンスを向上させるためのオブジェクトのキャッシュ。
- RMIまたはその他のRPCメカニズムを使用した分散システムでのオブジェクトの転送。
シリアライズドエンティティパターンの利点とトレードオフ
利点
- オブジェクト状態の保存と復元のプロセスを簡素化します。
- システムのさまざまな部分間でのオブジェクトの転送を容易にします。
- 手動のシリアライゼーションとデシリアライゼーションのための定型コードを削減します。
トレードオフ
- 適切に処理されない場合、セキュリティリスクが発生する可能性があります(例:デシリアライゼーション攻撃)。
- シリアライズされた形式は、人間が簡単に読んだり編集したりできない場合があります。
- クラス構造を変更すると、以前にシリアライズされたデータとの互換性が損なわれる可能性があります。
関連するJavaデザインパターン
- データ転送オブジェクト(DTO):データをカプセル化してネットワーク経由で送信するために使用されます。 多くの場合、送信のためにシリアライズされます。
- Memento:多くの場合、シリアライゼーションを使用して、オブジェクトの状態をキャプチャおよび復元する方法を提供します。
- プロキシ:プロキシは、リモートオブジェクトと対話するためのリクエストをシリアライズできます。