FC2ブログ
ヽ|∵|ゝ(Fantom) の 開発blog? ホーム »2014年06月
2014年06月の記事一覧

【Android】【Applet】【Java】interface を使ってインスタンスを生成する  


 前回の続き

 実際にインスタンス生成のコードは少々やっかいである。new 演算子を使うには型(クラス名)が必要で、そのコードがメインコードに大量にあると、もはや使い回しなど出来なくなる。しかし、完全に無くすことはできなくても、interface を使って、そのコードを減らすことはできる。それはインスタンス生成用のインターフェイスを作ってしまう事である。その基本コードを書いてみよう。

●インスタンス生成用のインターフェイス(InstanceFactory)
public interface InstanceFactory<T> {
public T newInstance();
}

 これはあくまでも簡単なものなので、必要に応じて色々作ってみると良いだろう。この手のインターフェイスは型を限定しないようにジェネリクス型を使う。とりあえず、ここでは実装には匿名クラスで定義してみよう。もちろん通常のクラスに implements して使っても構わない。

(参考)ジェネリクス型
(参考)総称型色々

●Android 版 インスタンス生成用のインターフェイス実装(匿名クラス)
InstanceFactory<XImage> factory = new InstanceFactory<XImage>() {
@Override
public XImage newInstance() {
return new AndroidImage();
}
};

●Applet 版 インスタンス生成用のインターフェイス実装(匿名クラス)
InstanceFactory<XImage> factory = new InstanceFactory<XImage>() {
@Override
public XImage newInstance() {
return new AppletImage();
}
};

 どちらもインスタンスを生成して返してるだけである。

 これが既にどこかに定義してあるとして、前回のメインコードを書き換えてみよう。

●インスタンス生成用のインターフェイス(InstanceFactory)がそれぞれ定義してあるとして、メインコードを書き換えてみる(共通)
//インスタンスを生成
XImage xImg = factory.newInstance();
//100 x 200 で画像を生成
xImg.createImage(100, 200);
dispSize(xImg);

 これなら、どちらのプラットフォームでも使える事がわかるだろう。定義部分は簡易フレームワークで使った XActivity, XApplet のような抽象クラスに定義してしまうという手もある。頻繁に使うものなら、XFramework にメソッド追加しても良いだろう。

 また、これを使えばメソッド内でインスタンス生成などもやり易くなる。簡単な例を挙げてみよう。

●インスタンス生成用のインターフェイスを引数にして画像を生成する(共通)
public XImage createImage(int width, int height, InstanceFactory<? extends XImage> factory) {
XImage xImg = factory.newInstance();
xImg.createImage(width, height);
return xImg;
}

//メインでは...
XImage xImg = createImage(100, 200, factory);
dispSize(xImg);

 この方法なら、すべて共通のコードで書けることがわかるだろう。もちろんこれ以外の XImage インターフェイスを持ったインスタンス生成インターフェイスを定義すれば、そのままオブジェクトを入れ替えても、使えるという利点もある。

 配列などもインターフェイスに定義可能だ。既存の InstanceFactory 少し改造してみよう。

●インスタンス生成用のインターフェイス(InstanceFactory)を配列対応にしてみる
public interface InstanceFactory<T> {
public T newInstance();
public T[] newInstance(int length);
public T[][] newInstance(int col, int row);
}

●Android 版 インスタンス生成用のインターフェイス(InstanceFactory)配列対応 実装
InstanceFactory<XImage> factory = new InstanceFactory<XImage>() {
@Override
public XImage newInstance() {
return new AndroidImage();
}
@Override
public XImage[] newInstance(int length) {
XImage[] images = new XImage[length];
for (int i = 0; i < length; i++) {
images[i] = new AndroidImage();
}
return images;
}
@Override
public XImage[][] newInstance(int col, int row) {
XImage[][] images = new XImage[row][col];
for (int j = 0; j < row; j++) {
for (int i = 0; i < col; i++) {
images[j][i] = new AndroidImage();
}
}
return images;
}
};

●Applet 版 インスタンス生成用のインターフェイス(InstanceFactory)配列対応 実装
InstanceFactory<XImage> factory = new InstanceFactory<XImage>() {
@Override
public XImage newInstance() {
return new AppletImage();
}
@Override
public XImage[] newInstance(int length) {
XImage[] images = new XImage[length];
for (int i = 0; i < length; i++) {
images[i] = new AppletImage();
}
return images;
}
@Override
public XImage[][] newInstance(int col, int row) {
XImage[][] images = new XImage[row][col];
for (int j = 0; j < row; j++) {
for (int i = 0; i < col; i++) {
images[j][i] = new AppletImage();
}
}
return images;
}
};


 実際の利用において、画像生成が少々面倒だと思ったら、コンストラクタを付け加えるのも良いだろう。画像生成用のコンストラクタと InstanceFactory を改造した XImageFactory インターフェイスを作ってみる。

●Android 版 画像ラッパークラス(AndroidImage)に画像生成のコンストラクタを付け加える
public final class AndroidImage implements XImage {
private Bitmap image;

//コンストラクタ
public AndroidImage() {
}
//画像生成のコンストラクタ
public AndroidImage(int width, int height) {
createImage(width, height);
}

@Override
public void createImage(int width, int height) {
this.image = Bitmap.createBitmap(width, height, Config.ARGB_8888);
}
@Override
public int getWidth() {
return image.getWidth();
}
@Override
public int getHeight() {
return image.getHeight();
}
}

●Applet 版 画像ラッパークラス(AppletImage)に画像生成のコンストラクタを付け加える
public final class AppletImage implements XImage {
private BufferedImage image;

//コンストラクタ
public AppletImage() {
}
//画像生成のコンストラクタ
public AppletImage(int width, int height) {
createImage(width, height);
}

@Override
public void createImage(int width, int height) {
this.image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
}
@Override
public int getWidth() {
return image.getWidth();
}
@Override
public int getHeight() {
return image.getHeight();
}
}

●インスタンス生成用のインターフェイスを画像生成用に改造する(XImageFactory)
public interface XImageFactory<T> {
public T newInstance(int width, int height);
public T[] newInstance(int width, int height, int length);
public T[][] newInstance(int width, int height, int col, int row);
}

 XImageFactory インターフェイスはよく使うのであれば、匿名ではなく、クラスに実装しても良い。

●Android 版画像生成用のインターフェイス(XImageFactory)をクラスに実装(AndroidImageFactory)
public final class AndroidImageFactory implements XImageFactory<AndroidImage> {
//コンストラクタ
public AndroidImageFactory() {
}

@Override
public AndroidImage newInstance(int width, int height) {
return new AndroidImage(width, height);
}
@Override
public AndroidImage[] newInstance(int width, int height, int length) {
AndroidImage[] images = new AndroidImage[length];
for (int i = 0; i < length; i++) {
images[i] = new AndroidImage(width, height);
}
return images;
}
@Override
public AndroidImage[][] newInstance(int width, int height, int col, int row) {
AndroidImage[][] images = new AndroidImage[row][col];
for (int j = 0; j < row; j++) {
for (int i = 0; i < col; i++) {
images[j][i] = new AndroidImage(width, height);
}
}
return images;
}
}

●Applet 版画像生成用のインターフェイス(XImageFactory)をクラスに実装(AppletImageFactory)
public final class AppletImageFactory implements XImageFactory<AppletImage> {
//コンストラクタ
public AppletImageFactory() {
}

@Override
public AppletImage newInstance(int width, int height) {
return new AppletImage(width, height);
}
@Override
public AppletImage[] newInstance(int width, int height, int length) {
AppletImage[] images = new AppletImage[length];
for (int i = 0; i < length; i++) {
images[i] = new AppletImage(width, height);
}
return images;
}
@Override
public AppletImage[][] newInstance(int width, int height, int col, int row) {
AppletImage[][] images = new AppletImage[row][col];
for (int j = 0; j < row; j++) {
for (int i = 0; i < col; i++) {
images[j][i] = new AppletImage(width, height);
}
}
return images;
}
}

●インスタンス生成インターフェイスの実装クラスを生成(Android 版)
XImageFactory<? extends XImage> factory = new AndroidImageFactory();

●インスタンス生成インターフェイスの実装クラスを生成(Applet 版)
XImageFactory<? extends XImage> factory = new AppletImageFactory();

●メインコードでは...
//インスタンス生成(100 x 200 で画像を生成)
XImage xImg = factory.newInstance(100, 200);
dispSize(xImg);

 実装クラスの左辺は XImageFactory<? extends XImage> となってるが、実装クラスの型でも良い。ここでは見た目上、 XImage の派生クラスと解りやすいように表記した。

 ここまで来れば、もうメインコードはほとんど共通化できる。new 演算子は極力使わず、factory のインターフェイスを使って、インスタンスを生成するコードで書いて置けば、プラットフォーム依存の少ないコードになることが分かるだろう。新たにプラットフォームが加わった場合も、その画像ラッパークラスを作れば、そのまま使える。factory はメソッドの引数にもできるので、色々とやってみると良いだろう。

●factory をメソッドの引数にする(あまりコードに意味はない)
public XImage[][] createImages(int width, int height, int col, int row, XImageFactory<? extends XImage> factory) {
return factory.newInstance(width, height, col, row);
}


 以下は、実際の画像オブジェクトラッパークラスを使ったデモ。Applet 版と Android 版の2種類作ってあるが、どちらもメイン部分は同じコードで書かれている(というより同じコードを参照している)。


サンプルデモ:つかさんパズル
Applet 版のサンプル (PC[IE]でアクセス)
Android 版のサンプル (Android2.2以降でアクセス)
(解説) Android と Applet の互換ってできるもんだね


(関連記事)
【Android】【Applet】【Java】interface を使って独自のラッパークラスを作る
【Android】【Applet】【Java】interface と abstract の使い方・違いとは~簡単なフレームワークを作って、考えてみる
【Java】interface を使って簡単なコールバック機能を作る
【Android】【Java】clone() を使ったオブジェクト複製


関連記事
スポンサーサイト



category: Java

thread: プログラミング

janre: コンピュータ

tb: 0   cm: --


プロフィール

Social

検索フォーム

全記事一覧

カテゴリ

ユーザータグ

最新記事

リンク

PR