SlideShare ist ein Scribd-Unternehmen logo
1 von 67
Downloaden Sie, um offline zu lesen
実装パターン
リファクタリングでよく使う7つの基本的な実装パターン
牧 竜也
Androidアプリ開発エンジニア
#1
public SearchRequest(String query, String lang,
String order, String sort) {
this(query, lang, order, sort, LIMIT, PAGE);
}
public SearchRequest(String query, String lang,
String order, String sort,
int limit, int page) {
mUrl = buildUrl(query, lang, order, sort, limit, page);
}
パラメータの多い

コンストラクタ
同じ型が連続すると
型チェックに弱い
public SearchRequest(String query, String lang,
String order, String sort) {
this(query, lang, order, sort, LIMIT, PAGE);
}
public SearchRequest(String query, String lang,
String order, String sort,
int limit, int page) {
mUrl = buildUrl(query, lang, order, sort, limit, page);
}
任意のパラメータも
与える必要がある
public SearchRequest(String query, String lang,
String order, String sort) {
this(query, lang, order, sort, LIMIT, PAGE);
}
public SearchRequest(String query, String lang,
String order, String sort,
int limit, int page) {
mUrl = buildUrl(query, lang, order, sort, limit, page);
}
Builder Pattern
public class Builder {
private final String mQuery;
private String mOrder;
private String mSort;
private String mLang;
public Builder(String query) {
mQuery = query;
}
public Builder setOrder(String order) {
mOrder = order;
return this;
}
public Builder setSort(String sort) {
mSort = sort;
return this;
}
...
public SearchRequest build() {
return new SearchRequest(this);
}
}
強制するのは
必須パラメータのみ
任意パラメータは
メソッドから与える
public class Builder {
private final String mQuery;
private String mOrder;
private String mSort;
private String mLang;
public Builder(String query) {
mQuery = query;
}
public Builder setOrder(String order) {
mOrder = order;
return this;
}
public Builder setSort(String sort) {
mSort = sort;
return this;
}
...
public SearchRequest build() {
return new SearchRequest(this);
}
}
Request request = new SearchRequest.Builder("Java")
.setLang("ja")
.setOrder("date")
.setSort("desc")
.setLimit(100)
.setPage(2)
.build();
インスタンス生成時の
可読性が向上
インスタンス生成時の可読性が向上
#2
public void setPadding(int left, int top,
int right, int bottom) {
...
}
パラメータの多い

メソッド
public void setPadding(int left, int top,
int right, int bottom) {
...
}
同じ型が連続すると
型チェックに弱い
Parameter Object
public class Padding {
public int left;
public int top;
public int right;
public int bottom;
}
関連するパラメータを
1つのクラスとして定義
Padding padding = new Padding();
padding.left = 10;
padding.top = 20;
padding.right = 10;
padding.bottom = 20;
object.setPadding(padding);
切り出したクラスを

パラメータとして与える
メソッド呼び出し時の可読性が向上
#3
public int getItemCount() {
if (mCursor == null) {
return 0;
}
return mCursor.getCount();
}
public long getItemId(int position) {
if (mCursor == null) {
return NO_ID;
}
mCursor.moveToPosition(position);
return mCursor.getLong(mRowIdColumn);
}
public Cursor changeCursor(Cursor cursor) {
Cursor oldCursor = mCursor;
mCursor = cursor;
return oldCursor;
}
Nullableな
フィールドを持つクラス
Nullになりうる
引数をそのまま受け取る
public int getItemCount() {
if (mCursor == null) {
return 0;
}
return mCursor.getCount();
}
public long getItemId(int position) {
if (mCursor == null) {
return NO_ID;
}
mCursor.moveToPosition(position);
return mCursor.getLong(mRowIdColumn);
}
public Cursor changeCursor(Cursor cursor) {
Cursor oldCursor = mCursor;
mCursor = cursor;
return oldCursor;
}
public int getItemCount() {
if (mCursor == null) {
return 0;
}
return mCursor.getCount();
}
public long getItemId(int position) {
if (mCursor == null) {
return NO_ID;
}
mCursor.moveToPosition(position);
return mCursor.getLong(mRowIdColumn);
}
public Cursor changeCursor(Cursor cursor) {
Cursor oldCursor = mCursor;
mCursor = cursor;
return oldCursor;
}
Nullチェックが点在し
実装が複雑化
Null Object
public class NullCursor implements Cursor {
@Override
public int getCount() {
return 0;
}
@Override
public int getPosition() {
return 0;
}
@Override
public boolean move(int offset) {
return true;
}
@Override
public boolean moveToPosition(int position) {
return true;
}
...
}
適切な振舞をする
Null Objectを定義
@Override
public int getItemCount() {
return mCursor.getCount();
}
@Override
public long getItemId(int position) {
mCursor.moveToPosition(position);
return mCursor.getLong(mRowIdColumn);
}
public Cursor changeCursor(Cursor cursor) {
Cursor oldCursor = mCursor;
if (mCursor == null) {
mCursor = new NullCursor();
} else {
mCursor = cursor;
}
return oldCursor;
}
Nullが与えられたら
Null Objectを代わりに利用
@Override
public int getItemCount() {
return mCursor.getCount();
}
@Override
public long getItemId(int position) {
mCursor.moveToPosition(position);
return mCursor.getLong(mRowIdColumn);
}
public Cursor changeCursor(Cursor cursor) {
Cursor oldCursor = mCursor;
if (mCursor == null) {
mCursor = new NullCursor();
} else {
mCursor = cursor;
}
return oldCursor;
}
他の処理では
Nullチェックが不要
Nullチェックが減りコードがシンプルに
#4
public class UpdateTask extends Task {
@Override
public void execute() throws TaskException {
SQLiteDatabase db = mHelper.getWritableDatabase();
try {
db.beginTransaction();
db.update(TABLE, mValues, mWhere, mArgs);
db.setTransactionSuccessful();
} catch (SQLiteException e) {
throw new TaskException(e);
} finally {
db.endTransaction();
}
}
}
DB操作など
定型的な処理が多いクラス
責務ごとに
複数のクラスが存在
public class DeleteTask extends Task {
@Override
public void execute() throws TaskException {
SQLiteDatabase db = mHelper.getWritableDatabase();
try {
db.beginTransaction();
db.delete(TABLE, mWhere, mArgs);
db.setTransactionSuccessful();
} catch (SQLiteException e) {
throw new TaskException(e);
} finally {
db.endTransaction();
}
}
}
複数のサブクラスで

似たような処理を実装
public class XxxTask extends Task {
@Override
public void execute() throws TaskException {
SQLiteDatabase db = mHelper.getWritableDatabase();
try {
db.beginTransaction();
db.doXxx();
db.setTransactionSuccessful();
} catch (SQLiteException e) {
throw new TaskException(e);
} finally {
db.endTransaction();
}
}
}
Templete Method
public abstract class SQLiteTask extends Task {
public final void execute() throws TaskException {
SQLiteDatabase db = mHelper.getWritableDatabase();
try {
db.beginTransaction();
runInTx(db);
db.setTransactionSuccessful();
} catch (SQLiteException e) {
throw new TaskException(e);
} finally {
db.endTransaction();
}
}
protected abstract void runInTx(SQLiteDatabase db)
throws SQLiteException;
}
定型処理を

抽象クラスで定義
public abstract class SQLiteTask extends Task { {
public final void execute() throws TaskException {
SQLiteDatabase db = mHelper.getWritableDatabase();
try {
db.beginTransaction();
runInTx(db);
db.setTransactionSuccessful();
} catch (SQLiteException e) {
throw new TaskException(e);
} finally {
db.endTransaction();
}
}
protected abstract void runInTx(SQLiteDatabase db)
throws SQLiteException;
}
サブクラスの担当は
抽象メソッドとして定義
public class UpdateTask extends SQLiteTask {
@Override
protected void runInTx(SQLiteDatabase db)
throws SQLiteException {
db.update(TABLE, mValues, mWhere, mArgs);
}
}
定型処理以外は
各サブクラスで実装
public class DeleteTask extends SQLiteTask {
@Override
protected void runInTx(SQLiteDatabase db)
throws SQLiteException {
db.delete(TABLE, mWhere, mArgs);
}
}
定型処理以外は
各サブクラスで実装
重複コードがなくなりシンプルに
#5
public class ViewAnimator {
private final Animation mAnimation;
private final Animator mAnimator;
public ViewAnimator(int from, int to) {
if (Build.VERSION.SDK_INT <
Build.VERSION_CODES.HONEYCOMB) {
mAnimation = ValueAnimation.ofInt(from, to);
mAnimator = null;
} else {
mAnimation = null;
mAnimator = ValueAnimator.ofInt(from, to);
}
}
...
public void start() {
if (Build.VERSION.SDK_INT <
Build.VERSION_CODES.HONEYCOMB) {
mView.start(mAnimation);
} else {
mAnimator.start();
}
}
}
APIバージョンに応じて
異なるAPIやクラスを切替
バージョン判定が点在し
クラスやメソッドを切替
public class ViewAnimator {
private final Animation mAnimation;
private final Animator mAnimator;
public ViewAnimator(int from, int to) {
if (Build.VERSION.SDK_INT <
Build.VERSION_CODES.HONEYCOMB) {
mAnimation = ValueAnimation.ofInt(from, to);
mAnimator = null;
} else {
mAnimation = null;
mAnimator = ValueAnimator.ofInt(from, to);
}
}
...
public void start() {
if (Build.VERSION.SDK_INT <
Build.VERSION_CODES.HONEYCOMB) {
mView.start(mAnimation);
} else {
mAnimator.start();
}
}
}
Adapter Pattern
互換性担保のための

共通インターフェースを定義
public abstract class ViewAnimator {
public ViewAnimator(int from, int to) {
...
}
public abstract void setDuration(long duration);
public abstract void setInterpolator(Interpolator i);
public abstract void start();
}
各サブクラスは
複数ではなく単一責務を負う
public class OldViewAnimator extends ViewAnimator {
private Animation mAnimation;
private View mView;
...
@Override
public void setDuration(long duration) {
mAnimation.setDuration(duration);
}
@Override
public void setInterpolator(Interpolator i) {
mAnimation.setInterpolator(i);
}
@Override
public void start() {
mView.startAnimation(mAnimation);
}
}
public class NewViewAnimator extends ViewAnimator {
private Animator mAnimator;
private View mView;
...
@Override
public void setDuration(long duration) {
mAnimator.setDuration(duration);
}
@Override
public void setInterpolator(Interpolator i) {
mAnimator.setInterpolator(i);
}
@Override
public void start() {
mAnimator.start();
}
}
各サブクラスは
複数ではなく単一責務を負う
public static ViewAnimator create(int version,
int from, int to) {
if (version < Build.VERSION_CODES.HONEYCOMB) {
return new OldViewAnimator(from, to);
} else {
return new NewViewAnimator(from, to);
}
}
インスタンスの生成は
Factory methodで隠蔽
統一されたインターフェースでシンプルに
#6
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int itemId = item.getItemId();
if (itemId == R.id.action_refresh) {
refresh();
return true;
} else if (itemId == R.id.action_edit) {
edit();
return true;
} else if (itemId == R.id.action_delete) {
delete();
return true;
} else if (itemId == R.id.action_clear) {
clear();
return true;
}
return super.onOptionsItemSelected(item);
}
条件によって
処理をディスパッチ
条件が増えると
条件分岐が肥大化
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int itemId = item.getItemId();
if (itemId == R.id.action_refresh) {
refresh();
return true;
} else if (itemId == R.id.action_edit) {
edit();
return true;
} else if (itemId == R.id.action_delete) {
delete();
return true;
} else if (itemId == R.id.action_clear) {
clear();
return true;
} else if (itemId == R.id.action_setting) {
showSetting();
return true;
} else if (itemId == R.id.action_help) {
showHelp();
return true;
}
return super.onOptionsItemSelected(item);
}
private void refresh() {
...
}
private void edit() {
...
}
private void delete() {
...
}
private void clear() {
...
}
private void showSetting() {
...
}
private void showHelp() {
...
}
メソッドも増えて
クラスも肥大化
Command Pattern
public interface Command {
boolean execute();
}
各処理に共通する
インターフェースを定義
public class RefreshCommand implements Command {
@Override
public boolean execute() {
...
return true;
}
}
処理ごとに
サブクラスを作成
mCommands = new SparseArray<>();
mCommands.append(
R.id.action_edit, new EditCommand());
mCommands.append(
R.id.action_delete, new DeleteCommand());
mCommands.append(
R.id.action_clear, new ClearCommand());
mCommands.append(
R.id.action_refresh, new RefreshCommand());
コマンドの識別子がキーの
コマンドマップを定義
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int itemId = item.getItemId();
Command command = mCommands.get(
itemId, new NullCommand());
return command.execute(getApplicationContext());
}
コマンドマップから
コマンドを引き当てて実行
巨大な条件分岐がなくなりシンプルに
#7
public void changeState(int state) {
if (state == STATE_LOADING) {
mLoadingView.setVisibility(View.VISIBLE);
mSuccessView.setVisibility(View.GONE);
mFailureView.setVisibility(View.GONE);
} else if (state == STATE_SUCCESS) {
mLoadingView.setVisibility(View.GONE);
mSuccessView.setVisibility(View.VISIBLE);
mFailureView.setVisibility(View.GONE);
} else if (state == STATE_FAILURE) {
mLoadingView.setVisibility(View.GONE);
mSuccessView.setVisibility(View.GONE);
mFailureView.setVisibility(View.VISIBLE);
}
}
Viewの表示切替などで
複雑な条件分岐
public void changeState(int state) {
if (state == STATE_LOADING) {
mLoadingView.setVisibility(View.VISIBLE);
mSuccessView.setVisibility(View.GONE);
mFailureView.setVisibility(View.GONE);
} else if (state == STATE_SUCCESS) {
mLoadingView.setVisibility(View.GONE);
mSuccessView.setVisibility(View.VISIBLE);
mFailureView.setVisibility(View.GONE);
} else if (state == STATE_FAILURE) {
mLoadingView.setVisibility(View.GONE);
mSuccessView.setVisibility(View.GONE);
mFailureView.setVisibility(View.VISIBLE);
} else if (state == STATE_SETTING) {
...
} else if (state == STATE_INITIAL) {
...
}
}
状態が増えると
条件分岐が更に肥大化
Double Dispatch
public enum State {
LOADING {
@Override
void change(StatefulFrameLayout layout) {
layout.getLoadingView()
.setVisibility(View.VISIBLE);
layout.getSuccessView()
.setVisibility(View.GONE);
layout.getFailureView()
.setVisibility(View.GONE);
}
},
SUCCESS {
@Override
void change(StatefulFrameLayout layout) {
layout.getLoadingView()
.setVisibility(View.GONE);
layout.getSuccessView()
.setVisibility(View.VISIBLE);
layout.getFailureView()
.setVisibility(View.GONE);
}
},
...
};
abstract void change(StatefulFrameLayout layout);
}
抽象メソッド化して
サブクラスに実装を強制
public enum State {
LOADING {
@Override
void change(StatefulFrameLayout layout) {
layout.getLoadingView()
.setVisibility(View.VISIBLE);
layout.getSuccessView()
.setVisibility(View.GONE);
layout.getFailureView()
.setVisibility(View.GONE);
}
},
SUCCESS {
@Override
void change(StatefulFrameLayout layout) {
layout.getLoadingView()
.setVisibility(View.GONE);
layout.getSuccessView()
.setVisibility(View.VISIBLE);
layout.getFailureView()
.setVisibility(View.GONE);
}
},
...
};
abstract void change(StatefulFrameLayout layout);
}
実際の処理は
サブクラスや列挙型で実装
public enum State {
LOADING {
@Override
void change(StatefulFrameLayout layout) {
layout.getLoadingView()
.setVisibility(View.VISIBLE);
layout.getSuccessView()
.setVisibility(View.GONE);
layout.getFailureView()
.setVisibility(View.GONE);
}
},
SUCCESS {
@Override
void change(StatefulFrameLayout layout) {
layout.getLoadingView()
.setVisibility(View.GONE);
layout.getSuccessView()
.setVisibility(View.VISIBLE);
layout.getFailureView()
.setVisibility(View.GONE);
}
},
...
};
abstract void change(StatefulFrameLayout layout);
}
状態ごとに
サブクラスや列挙型を定義
public void changeState(State state) {
state.change(this);
}
自身をパラメータとして
メソッドを呼び出す
肥大化しがちな条件分岐がシンプルに
まとめ
実装パターンを適切に使って
効果的にリファクタリング

Weitere ähnliche Inhalte

Was ist angesagt?

LINQソースでGO!
LINQソースでGO!LINQソースでGO!
LINQソースでGO!Kouji Matsui
 
C#を始めたばかりの人へのLINQ to Objects
C#を始めたばかりの人へのLINQ to ObjectsC#を始めたばかりの人へのLINQ to Objects
C#を始めたばかりの人へのLINQ to ObjectsFumitaka Yamada
 
Javaセキュアコーディングセミナー東京第1回演習の解説
Javaセキュアコーディングセミナー東京第1回演習の解説Javaセキュアコーディングセミナー東京第1回演習の解説
Javaセキュアコーディングセミナー東京第1回演習の解説JPCERT Coordination Center
 
60分で体験する Stream / Lambda
 ハンズオン
60分で体験する Stream / Lambda
 ハンズオン60分で体験する Stream / Lambda
 ハンズオン
60分で体験する Stream / Lambda
 ハンズオンHiroto Yamakawa
 
C# 式木 (Expression Tree) ~ LINQをより深く理解するために ~
C# 式木 (Expression Tree) ~ LINQをより深く理解するために ~C# 式木 (Expression Tree) ~ LINQをより深く理解するために ~
C# 式木 (Expression Tree) ~ LINQをより深く理解するために ~Fujio Kojima
 
OpenFOAM の cyclic、cyclicAMI、cyclicACMI 条件について
OpenFOAM の cyclic、cyclicAMI、cyclicACMI 条件についてOpenFOAM の cyclic、cyclicAMI、cyclicACMI 条件について
OpenFOAM の cyclic、cyclicAMI、cyclicACMI 条件についてFumiya Nozaki
 
Flow.js
Flow.jsFlow.js
Flow.jsuupaa
 
Turbulence Models in OpenFOAM
Turbulence Models in OpenFOAMTurbulence Models in OpenFOAM
Turbulence Models in OpenFOAMFumiya Nozaki
 
C++0x 言語の未来を語る
C++0x 言語の未来を語るC++0x 言語の未来を語る
C++0x 言語の未来を語るAkira Takahashi
 
unique_ptrにポインタ以外のものを持たせるとき
unique_ptrにポインタ以外のものを持たせるときunique_ptrにポインタ以外のものを持たせるとき
unique_ptrにポインタ以外のものを持たせるときShintarou Okada
 
Effective modern C++ 勉強会 #3 Item 12
Effective modern C++ 勉強会 #3 Item 12Effective modern C++ 勉強会 #3 Item 12
Effective modern C++ 勉強会 #3 Item 12Keisuke Fukuda
 
OpenFOAM の境界条件をまとめよう!
OpenFOAM の境界条件をまとめよう!OpenFOAM の境界条件をまとめよう!
OpenFOAM の境界条件をまとめよう!Fumiya Nozaki
 
メタプログラミング C#
メタプログラミング C#メタプログラミング C#
メタプログラミング C#Fujio Kojima
 

Was ist angesagt? (16)

LINQソースでGO!
LINQソースでGO!LINQソースでGO!
LINQソースでGO!
 
C#を始めたばかりの人へのLINQ to Objects
C#を始めたばかりの人へのLINQ to ObjectsC#を始めたばかりの人へのLINQ to Objects
C#を始めたばかりの人へのLINQ to Objects
 
Javaセキュアコーディングセミナー東京第1回演習の解説
Javaセキュアコーディングセミナー東京第1回演習の解説Javaセキュアコーディングセミナー東京第1回演習の解説
Javaセキュアコーディングセミナー東京第1回演習の解説
 
Ajax 応用
Ajax 応用Ajax 応用
Ajax 応用
 
60分で体験する Stream / Lambda
 ハンズオン
60分で体験する Stream / Lambda
 ハンズオン60分で体験する Stream / Lambda
 ハンズオン
60分で体験する Stream / Lambda
 ハンズオン
 
C# 式木 (Expression Tree) ~ LINQをより深く理解するために ~
C# 式木 (Expression Tree) ~ LINQをより深く理解するために ~C# 式木 (Expression Tree) ~ LINQをより深く理解するために ~
C# 式木 (Expression Tree) ~ LINQをより深く理解するために ~
 
OpenFOAM の cyclic、cyclicAMI、cyclicACMI 条件について
OpenFOAM の cyclic、cyclicAMI、cyclicACMI 条件についてOpenFOAM の cyclic、cyclicAMI、cyclicACMI 条件について
OpenFOAM の cyclic、cyclicAMI、cyclicACMI 条件について
 
Junit4
Junit4Junit4
Junit4
 
Flow.js
Flow.jsFlow.js
Flow.js
 
Turbulence Models in OpenFOAM
Turbulence Models in OpenFOAMTurbulence Models in OpenFOAM
Turbulence Models in OpenFOAM
 
C++0x 言語の未来を語る
C++0x 言語の未来を語るC++0x 言語の未来を語る
C++0x 言語の未来を語る
 
unique_ptrにポインタ以外のものを持たせるとき
unique_ptrにポインタ以外のものを持たせるときunique_ptrにポインタ以外のものを持たせるとき
unique_ptrにポインタ以外のものを持たせるとき
 
Effective modern C++ 勉強会 #3 Item 12
Effective modern C++ 勉強会 #3 Item 12Effective modern C++ 勉強会 #3 Item 12
Effective modern C++ 勉強会 #3 Item 12
 
OpenFOAM の境界条件をまとめよう!
OpenFOAM の境界条件をまとめよう!OpenFOAM の境界条件をまとめよう!
OpenFOAM の境界条件をまとめよう!
 
Bluespec @waseda(PDF)
Bluespec @waseda(PDF)Bluespec @waseda(PDF)
Bluespec @waseda(PDF)
 
メタプログラミング C#
メタプログラミング C#メタプログラミング C#
メタプログラミング C#
 

Ähnlich wie Implementation patterns

サーバーサイドでの非同期処理で色々やったよ
サーバーサイドでの非同期処理で色々やったよサーバーサイドでの非同期処理で色々やったよ
サーバーサイドでの非同期処理で色々やったよkoji lin
 
SpringOne 2GX 2014 参加報告 & Spring 4.1について #jsug
SpringOne 2GX 2014 参加報告 & Spring 4.1について #jsugSpringOne 2GX 2014 参加報告 & Spring 4.1について #jsug
SpringOne 2GX 2014 参加報告 & Spring 4.1について #jsugToshiaki Maki
 
基礎から見直す ASP.NET MVC の単体テスト自動化方法 ~ Windows Azure 関連もあるかも~
基礎から見直す ASP.NET MVC の単体テスト自動化方法 ~ Windows Azure 関連もあるかも~基礎から見直す ASP.NET MVC の単体テスト自動化方法 ~ Windows Azure 関連もあるかも~
基礎から見直す ASP.NET MVC の単体テスト自動化方法 ~ Windows Azure 関連もあるかも~normalian
 
GoF デザインパターン 2009
GoF デザインパターン 2009GoF デザインパターン 2009
GoF デザインパターン 2009miwarin
 
Sencha ug3 siesta_share
Sencha ug3 siesta_shareSencha ug3 siesta_share
Sencha ug3 siesta_share久司 中村
 
JEP280: Java 9 で文字列結合の処理が変わるぞ!準備はいいか!? #jjug_ccc
JEP280: Java 9 で文字列結合の処理が変わるぞ!準備はいいか!? #jjug_cccJEP280: Java 9 で文字列結合の処理が変わるぞ!準備はいいか!? #jjug_ccc
JEP280: Java 9 で文字列結合の処理が変わるぞ!準備はいいか!? #jjug_cccYujiSoftware
 
ECMAScript6による関数型プログラミング
ECMAScript6による関数型プログラミングECMAScript6による関数型プログラミング
ECMAScript6による関数型プログラミングTanUkkii
 
エンタープライズ分野での実践AngularJS
エンタープライズ分野での実践AngularJSエンタープライズ分野での実践AngularJS
エンタープライズ分野での実践AngularJSAyumi Goto
 
Apache Torqueについて
Apache TorqueについてApache Torqueについて
Apache Torqueについてtako pons
 
自作node.jsフレームワークとnginxを使ってラジオサイトを作ってみた
自作node.jsフレームワークとnginxを使ってラジオサイトを作ってみた自作node.jsフレームワークとnginxを使ってラジオサイトを作ってみた
自作node.jsフレームワークとnginxを使ってラジオサイトを作ってみたYuki Takei
 
「Windows 8 ストア アプリ開発 tips」 hokuriku.net vol.11 (2013年1月26日)
「Windows 8 ストア アプリ開発 tips」  hokuriku.net vol.11 (2013年1月26日)「Windows 8 ストア アプリ開発 tips」  hokuriku.net vol.11 (2013年1月26日)
「Windows 8 ストア アプリ開発 tips」 hokuriku.net vol.11 (2013年1月26日)Fujio Kojima
 
OSSから学ぶSwift実践テクニック
OSSから学ぶSwift実践テクニックOSSから学ぶSwift実践テクニック
OSSから学ぶSwift実践テクニック庸介 高橋
 
Next2Dで始めるゲーム開発 - Game Development Starting with Next2D
Next2Dで始めるゲーム開発  - Game Development Starting with Next2DNext2Dで始めるゲーム開発  - Game Development Starting with Next2D
Next2Dで始めるゲーム開発 - Game Development Starting with Next2DToshiyuki Ienaga
 
Java9直前!最近のJava復習ハンズオン
Java9直前!最近のJava復習ハンズオンJava9直前!最近のJava復習ハンズオン
Java9直前!最近のJava復習ハンズオンHiroto Yamakawa
 
速くなければスマフォじゃない - インターンバージョン-
速くなければスマフォじゃない - インターンバージョン-速くなければスマフォじゃない - インターンバージョン-
速くなければスマフォじゃない - インターンバージョン-Kazunari Hara
 
クラウド時代の並列分散処理技術
クラウド時代の並列分散処理技術クラウド時代の並列分散処理技術
クラウド時代の並列分散処理技術Koichi Fujikawa
 
T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門伸男 伊藤
 

Ähnlich wie Implementation patterns (20)

サーバーサイドでの非同期処理で色々やったよ
サーバーサイドでの非同期処理で色々やったよサーバーサイドでの非同期処理で色々やったよ
サーバーサイドでの非同期処理で色々やったよ
 
SpringOne 2GX 2014 参加報告 & Spring 4.1について #jsug
SpringOne 2GX 2014 参加報告 & Spring 4.1について #jsugSpringOne 2GX 2014 参加報告 & Spring 4.1について #jsug
SpringOne 2GX 2014 参加報告 & Spring 4.1について #jsug
 
Pfi Seminar 2010 1 7
Pfi Seminar 2010 1 7Pfi Seminar 2010 1 7
Pfi Seminar 2010 1 7
 
基礎から見直す ASP.NET MVC の単体テスト自動化方法 ~ Windows Azure 関連もあるかも~
基礎から見直す ASP.NET MVC の単体テスト自動化方法 ~ Windows Azure 関連もあるかも~基礎から見直す ASP.NET MVC の単体テスト自動化方法 ~ Windows Azure 関連もあるかも~
基礎から見直す ASP.NET MVC の単体テスト自動化方法 ~ Windows Azure 関連もあるかも~
 
GoF デザインパターン 2009
GoF デザインパターン 2009GoF デザインパターン 2009
GoF デザインパターン 2009
 
Sencha ug3 siesta_share
Sencha ug3 siesta_shareSencha ug3 siesta_share
Sencha ug3 siesta_share
 
JEP280: Java 9 で文字列結合の処理が変わるぞ!準備はいいか!? #jjug_ccc
JEP280: Java 9 で文字列結合の処理が変わるぞ!準備はいいか!? #jjug_cccJEP280: Java 9 で文字列結合の処理が変わるぞ!準備はいいか!? #jjug_ccc
JEP280: Java 9 で文字列結合の処理が変わるぞ!準備はいいか!? #jjug_ccc
 
Project lambda
Project lambdaProject lambda
Project lambda
 
ECMAScript6による関数型プログラミング
ECMAScript6による関数型プログラミングECMAScript6による関数型プログラミング
ECMAScript6による関数型プログラミング
 
エンタープライズ分野での実践AngularJS
エンタープライズ分野での実践AngularJSエンタープライズ分野での実践AngularJS
エンタープライズ分野での実践AngularJS
 
Apache Torqueについて
Apache TorqueについてApache Torqueについて
Apache Torqueについて
 
自作node.jsフレームワークとnginxを使ってラジオサイトを作ってみた
自作node.jsフレームワークとnginxを使ってラジオサイトを作ってみた自作node.jsフレームワークとnginxを使ってラジオサイトを作ってみた
自作node.jsフレームワークとnginxを使ってラジオサイトを作ってみた
 
「Windows 8 ストア アプリ開発 tips」 hokuriku.net vol.11 (2013年1月26日)
「Windows 8 ストア アプリ開発 tips」  hokuriku.net vol.11 (2013年1月26日)「Windows 8 ストア アプリ開発 tips」  hokuriku.net vol.11 (2013年1月26日)
「Windows 8 ストア アプリ開発 tips」 hokuriku.net vol.11 (2013年1月26日)
 
OSSから学ぶSwift実践テクニック
OSSから学ぶSwift実践テクニックOSSから学ぶSwift実践テクニック
OSSから学ぶSwift実践テクニック
 
Next2Dで始めるゲーム開発 - Game Development Starting with Next2D
Next2Dで始めるゲーム開発  - Game Development Starting with Next2DNext2Dで始めるゲーム開発  - Game Development Starting with Next2D
Next2Dで始めるゲーム開発 - Game Development Starting with Next2D
 
Entity Framework
Entity FrameworkEntity Framework
Entity Framework
 
Java9直前!最近のJava復習ハンズオン
Java9直前!最近のJava復習ハンズオンJava9直前!最近のJava復習ハンズオン
Java9直前!最近のJava復習ハンズオン
 
速くなければスマフォじゃない - インターンバージョン-
速くなければスマフォじゃない - インターンバージョン-速くなければスマフォじゃない - インターンバージョン-
速くなければスマフォじゃない - インターンバージョン-
 
クラウド時代の並列分散処理技術
クラウド時代の並列分散処理技術クラウド時代の並列分散処理技術
クラウド時代の並列分散処理技術
 
T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門
 

Kürzlich hochgeladen

NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)
NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)
NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)NTT DATA Technology & Innovation
 
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアルLoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアルCRI Japan, Inc.
 
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。iPride Co., Ltd.
 
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。iPride Co., Ltd.
 
論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding
論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding
論文紹介:Selective Structured State-Spaces for Long-Form Video UnderstandingToru Tamaki
 
Utilizing Ballerina for Cloud Native Integrations
Utilizing Ballerina for Cloud Native IntegrationsUtilizing Ballerina for Cloud Native Integrations
Utilizing Ballerina for Cloud Native IntegrationsWSO2
 
Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)
Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)
Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)Hiroshi Tomioka
 
論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games
論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games
論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Gamesatsushi061452
 
知識ゼロの営業マンでもできた!超速で初心者を脱する、悪魔的学習ステップ3選.pptx
知識ゼロの営業マンでもできた!超速で初心者を脱する、悪魔的学習ステップ3選.pptx知識ゼロの営業マンでもできた!超速で初心者を脱する、悪魔的学習ステップ3選.pptx
知識ゼロの営業マンでもできた!超速で初心者を脱する、悪魔的学習ステップ3選.pptxsn679259
 
LoRaWANスマート距離検出センサー DS20L カタログ LiDARデバイス
LoRaWANスマート距離検出センサー  DS20L  カタログ  LiDARデバイスLoRaWANスマート距離検出センサー  DS20L  カタログ  LiDARデバイス
LoRaWANスマート距離検出センサー DS20L カタログ LiDARデバイスCRI Japan, Inc.
 
論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...
論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...
論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...Toru Tamaki
 
新人研修 後半 2024/04/26の勉強会で発表されたものです。
新人研修 後半        2024/04/26の勉強会で発表されたものです。新人研修 後半        2024/04/26の勉強会で発表されたものです。
新人研修 後半 2024/04/26の勉強会で発表されたものです。iPride Co., Ltd.
 

Kürzlich hochgeladen (12)

NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)
NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)
NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)
 
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアルLoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
 
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。
 
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
 
論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding
論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding
論文紹介:Selective Structured State-Spaces for Long-Form Video Understanding
 
Utilizing Ballerina for Cloud Native Integrations
Utilizing Ballerina for Cloud Native IntegrationsUtilizing Ballerina for Cloud Native Integrations
Utilizing Ballerina for Cloud Native Integrations
 
Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)
Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)
Observabilityは従来型の監視と何が違うのか(キンドリルジャパン社内勉強会:2022年10月27日発表)
 
論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games
論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games
論文紹介: The Surprising Effectiveness of PPO in Cooperative Multi-Agent Games
 
知識ゼロの営業マンでもできた!超速で初心者を脱する、悪魔的学習ステップ3選.pptx
知識ゼロの営業マンでもできた!超速で初心者を脱する、悪魔的学習ステップ3選.pptx知識ゼロの営業マンでもできた!超速で初心者を脱する、悪魔的学習ステップ3選.pptx
知識ゼロの営業マンでもできた!超速で初心者を脱する、悪魔的学習ステップ3選.pptx
 
LoRaWANスマート距離検出センサー DS20L カタログ LiDARデバイス
LoRaWANスマート距離検出センサー  DS20L  カタログ  LiDARデバイスLoRaWANスマート距離検出センサー  DS20L  カタログ  LiDARデバイス
LoRaWANスマート距離検出センサー DS20L カタログ LiDARデバイス
 
論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...
論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...
論文紹介:Video-GroundingDINO: Towards Open-Vocabulary Spatio-Temporal Video Groun...
 
新人研修 後半 2024/04/26の勉強会で発表されたものです。
新人研修 後半        2024/04/26の勉強会で発表されたものです。新人研修 後半        2024/04/26の勉強会で発表されたものです。
新人研修 後半 2024/04/26の勉強会で発表されたものです。
 

Implementation patterns

  • 3. #1
  • 4. public SearchRequest(String query, String lang, String order, String sort) { this(query, lang, order, sort, LIMIT, PAGE); } public SearchRequest(String query, String lang, String order, String sort, int limit, int page) { mUrl = buildUrl(query, lang, order, sort, limit, page); } パラメータの多い コンストラクタ
  • 5. 同じ型が連続すると 型チェックに弱い public SearchRequest(String query, String lang, String order, String sort) { this(query, lang, order, sort, LIMIT, PAGE); } public SearchRequest(String query, String lang, String order, String sort, int limit, int page) { mUrl = buildUrl(query, lang, order, sort, limit, page); }
  • 6. 任意のパラメータも 与える必要がある public SearchRequest(String query, String lang, String order, String sort) { this(query, lang, order, sort, LIMIT, PAGE); } public SearchRequest(String query, String lang, String order, String sort, int limit, int page) { mUrl = buildUrl(query, lang, order, sort, limit, page); }
  • 8. public class Builder { private final String mQuery; private String mOrder; private String mSort; private String mLang; public Builder(String query) { mQuery = query; } public Builder setOrder(String order) { mOrder = order; return this; } public Builder setSort(String sort) { mSort = sort; return this; } ... public SearchRequest build() { return new SearchRequest(this); } } 強制するのは 必須パラメータのみ
  • 9. 任意パラメータは メソッドから与える public class Builder { private final String mQuery; private String mOrder; private String mSort; private String mLang; public Builder(String query) { mQuery = query; } public Builder setOrder(String order) { mOrder = order; return this; } public Builder setSort(String sort) { mSort = sort; return this; } ... public SearchRequest build() { return new SearchRequest(this); } }
  • 10. Request request = new SearchRequest.Builder("Java") .setLang("ja") .setOrder("date") .setSort("desc") .setLimit(100) .setPage(2) .build(); インスタンス生成時の 可読性が向上
  • 12. #2
  • 13. public void setPadding(int left, int top, int right, int bottom) { ... } パラメータの多い メソッド
  • 14. public void setPadding(int left, int top, int right, int bottom) { ... } 同じ型が連続すると 型チェックに弱い
  • 16. public class Padding { public int left; public int top; public int right; public int bottom; } 関連するパラメータを 1つのクラスとして定義
  • 17. Padding padding = new Padding(); padding.left = 10; padding.top = 20; padding.right = 10; padding.bottom = 20; object.setPadding(padding); 切り出したクラスを パラメータとして与える
  • 19. #3
  • 20. public int getItemCount() { if (mCursor == null) { return 0; } return mCursor.getCount(); } public long getItemId(int position) { if (mCursor == null) { return NO_ID; } mCursor.moveToPosition(position); return mCursor.getLong(mRowIdColumn); } public Cursor changeCursor(Cursor cursor) { Cursor oldCursor = mCursor; mCursor = cursor; return oldCursor; } Nullableな フィールドを持つクラス
  • 21. Nullになりうる 引数をそのまま受け取る public int getItemCount() { if (mCursor == null) { return 0; } return mCursor.getCount(); } public long getItemId(int position) { if (mCursor == null) { return NO_ID; } mCursor.moveToPosition(position); return mCursor.getLong(mRowIdColumn); } public Cursor changeCursor(Cursor cursor) { Cursor oldCursor = mCursor; mCursor = cursor; return oldCursor; }
  • 22. public int getItemCount() { if (mCursor == null) { return 0; } return mCursor.getCount(); } public long getItemId(int position) { if (mCursor == null) { return NO_ID; } mCursor.moveToPosition(position); return mCursor.getLong(mRowIdColumn); } public Cursor changeCursor(Cursor cursor) { Cursor oldCursor = mCursor; mCursor = cursor; return oldCursor; } Nullチェックが点在し 実装が複雑化
  • 24. public class NullCursor implements Cursor { @Override public int getCount() { return 0; } @Override public int getPosition() { return 0; } @Override public boolean move(int offset) { return true; } @Override public boolean moveToPosition(int position) { return true; } ... } 適切な振舞をする Null Objectを定義
  • 25. @Override public int getItemCount() { return mCursor.getCount(); } @Override public long getItemId(int position) { mCursor.moveToPosition(position); return mCursor.getLong(mRowIdColumn); } public Cursor changeCursor(Cursor cursor) { Cursor oldCursor = mCursor; if (mCursor == null) { mCursor = new NullCursor(); } else { mCursor = cursor; } return oldCursor; } Nullが与えられたら Null Objectを代わりに利用
  • 26. @Override public int getItemCount() { return mCursor.getCount(); } @Override public long getItemId(int position) { mCursor.moveToPosition(position); return mCursor.getLong(mRowIdColumn); } public Cursor changeCursor(Cursor cursor) { Cursor oldCursor = mCursor; if (mCursor == null) { mCursor = new NullCursor(); } else { mCursor = cursor; } return oldCursor; } 他の処理では Nullチェックが不要
  • 28. #4
  • 29. public class UpdateTask extends Task { @Override public void execute() throws TaskException { SQLiteDatabase db = mHelper.getWritableDatabase(); try { db.beginTransaction(); db.update(TABLE, mValues, mWhere, mArgs); db.setTransactionSuccessful(); } catch (SQLiteException e) { throw new TaskException(e); } finally { db.endTransaction(); } } } DB操作など 定型的な処理が多いクラス
  • 30. 責務ごとに 複数のクラスが存在 public class DeleteTask extends Task { @Override public void execute() throws TaskException { SQLiteDatabase db = mHelper.getWritableDatabase(); try { db.beginTransaction(); db.delete(TABLE, mWhere, mArgs); db.setTransactionSuccessful(); } catch (SQLiteException e) { throw new TaskException(e); } finally { db.endTransaction(); } } }
  • 31. 複数のサブクラスで 似たような処理を実装 public class XxxTask extends Task { @Override public void execute() throws TaskException { SQLiteDatabase db = mHelper.getWritableDatabase(); try { db.beginTransaction(); db.doXxx(); db.setTransactionSuccessful(); } catch (SQLiteException e) { throw new TaskException(e); } finally { db.endTransaction(); } } }
  • 33. public abstract class SQLiteTask extends Task { public final void execute() throws TaskException { SQLiteDatabase db = mHelper.getWritableDatabase(); try { db.beginTransaction(); runInTx(db); db.setTransactionSuccessful(); } catch (SQLiteException e) { throw new TaskException(e); } finally { db.endTransaction(); } } protected abstract void runInTx(SQLiteDatabase db) throws SQLiteException; } 定型処理を 抽象クラスで定義
  • 34. public abstract class SQLiteTask extends Task { { public final void execute() throws TaskException { SQLiteDatabase db = mHelper.getWritableDatabase(); try { db.beginTransaction(); runInTx(db); db.setTransactionSuccessful(); } catch (SQLiteException e) { throw new TaskException(e); } finally { db.endTransaction(); } } protected abstract void runInTx(SQLiteDatabase db) throws SQLiteException; } サブクラスの担当は 抽象メソッドとして定義
  • 35. public class UpdateTask extends SQLiteTask { @Override protected void runInTx(SQLiteDatabase db) throws SQLiteException { db.update(TABLE, mValues, mWhere, mArgs); } } 定型処理以外は 各サブクラスで実装
  • 36. public class DeleteTask extends SQLiteTask { @Override protected void runInTx(SQLiteDatabase db) throws SQLiteException { db.delete(TABLE, mWhere, mArgs); } } 定型処理以外は 各サブクラスで実装
  • 38. #5
  • 39. public class ViewAnimator { private final Animation mAnimation; private final Animator mAnimator; public ViewAnimator(int from, int to) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { mAnimation = ValueAnimation.ofInt(from, to); mAnimator = null; } else { mAnimation = null; mAnimator = ValueAnimator.ofInt(from, to); } } ... public void start() { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { mView.start(mAnimation); } else { mAnimator.start(); } } } APIバージョンに応じて 異なるAPIやクラスを切替
  • 40. バージョン判定が点在し クラスやメソッドを切替 public class ViewAnimator { private final Animation mAnimation; private final Animator mAnimator; public ViewAnimator(int from, int to) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { mAnimation = ValueAnimation.ofInt(from, to); mAnimator = null; } else { mAnimation = null; mAnimator = ValueAnimator.ofInt(from, to); } } ... public void start() { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { mView.start(mAnimation); } else { mAnimator.start(); } } }
  • 42. 互換性担保のための 共通インターフェースを定義 public abstract class ViewAnimator { public ViewAnimator(int from, int to) { ... } public abstract void setDuration(long duration); public abstract void setInterpolator(Interpolator i); public abstract void start(); }
  • 43. 各サブクラスは 複数ではなく単一責務を負う public class OldViewAnimator extends ViewAnimator { private Animation mAnimation; private View mView; ... @Override public void setDuration(long duration) { mAnimation.setDuration(duration); } @Override public void setInterpolator(Interpolator i) { mAnimation.setInterpolator(i); } @Override public void start() { mView.startAnimation(mAnimation); } }
  • 44. public class NewViewAnimator extends ViewAnimator { private Animator mAnimator; private View mView; ... @Override public void setDuration(long duration) { mAnimator.setDuration(duration); } @Override public void setInterpolator(Interpolator i) { mAnimator.setInterpolator(i); } @Override public void start() { mAnimator.start(); } } 各サブクラスは 複数ではなく単一責務を負う
  • 45. public static ViewAnimator create(int version, int from, int to) { if (version < Build.VERSION_CODES.HONEYCOMB) { return new OldViewAnimator(from, to); } else { return new NewViewAnimator(from, to); } } インスタンスの生成は Factory methodで隠蔽
  • 47. #6
  • 48. @Override public boolean onOptionsItemSelected(MenuItem item) { int itemId = item.getItemId(); if (itemId == R.id.action_refresh) { refresh(); return true; } else if (itemId == R.id.action_edit) { edit(); return true; } else if (itemId == R.id.action_delete) { delete(); return true; } else if (itemId == R.id.action_clear) { clear(); return true; } return super.onOptionsItemSelected(item); } 条件によって 処理をディスパッチ
  • 49. 条件が増えると 条件分岐が肥大化 @Override public boolean onOptionsItemSelected(MenuItem item) { int itemId = item.getItemId(); if (itemId == R.id.action_refresh) { refresh(); return true; } else if (itemId == R.id.action_edit) { edit(); return true; } else if (itemId == R.id.action_delete) { delete(); return true; } else if (itemId == R.id.action_clear) { clear(); return true; } else if (itemId == R.id.action_setting) { showSetting(); return true; } else if (itemId == R.id.action_help) { showHelp(); return true; } return super.onOptionsItemSelected(item); }
  • 50. private void refresh() { ... } private void edit() { ... } private void delete() { ... } private void clear() { ... } private void showSetting() { ... } private void showHelp() { ... } メソッドも増えて クラスも肥大化
  • 52. public interface Command { boolean execute(); } 各処理に共通する インターフェースを定義
  • 53. public class RefreshCommand implements Command { @Override public boolean execute() { ... return true; } } 処理ごとに サブクラスを作成
  • 54. mCommands = new SparseArray<>(); mCommands.append( R.id.action_edit, new EditCommand()); mCommands.append( R.id.action_delete, new DeleteCommand()); mCommands.append( R.id.action_clear, new ClearCommand()); mCommands.append( R.id.action_refresh, new RefreshCommand()); コマンドの識別子がキーの コマンドマップを定義
  • 55. @Override public boolean onOptionsItemSelected(MenuItem item) { int itemId = item.getItemId(); Command command = mCommands.get( itemId, new NullCommand()); return command.execute(getApplicationContext()); } コマンドマップから コマンドを引き当てて実行
  • 57. #7
  • 58. public void changeState(int state) { if (state == STATE_LOADING) { mLoadingView.setVisibility(View.VISIBLE); mSuccessView.setVisibility(View.GONE); mFailureView.setVisibility(View.GONE); } else if (state == STATE_SUCCESS) { mLoadingView.setVisibility(View.GONE); mSuccessView.setVisibility(View.VISIBLE); mFailureView.setVisibility(View.GONE); } else if (state == STATE_FAILURE) { mLoadingView.setVisibility(View.GONE); mSuccessView.setVisibility(View.GONE); mFailureView.setVisibility(View.VISIBLE); } } Viewの表示切替などで 複雑な条件分岐
  • 59. public void changeState(int state) { if (state == STATE_LOADING) { mLoadingView.setVisibility(View.VISIBLE); mSuccessView.setVisibility(View.GONE); mFailureView.setVisibility(View.GONE); } else if (state == STATE_SUCCESS) { mLoadingView.setVisibility(View.GONE); mSuccessView.setVisibility(View.VISIBLE); mFailureView.setVisibility(View.GONE); } else if (state == STATE_FAILURE) { mLoadingView.setVisibility(View.GONE); mSuccessView.setVisibility(View.GONE); mFailureView.setVisibility(View.VISIBLE); } else if (state == STATE_SETTING) { ... } else if (state == STATE_INITIAL) { ... } } 状態が増えると 条件分岐が更に肥大化
  • 61. public enum State { LOADING { @Override void change(StatefulFrameLayout layout) { layout.getLoadingView() .setVisibility(View.VISIBLE); layout.getSuccessView() .setVisibility(View.GONE); layout.getFailureView() .setVisibility(View.GONE); } }, SUCCESS { @Override void change(StatefulFrameLayout layout) { layout.getLoadingView() .setVisibility(View.GONE); layout.getSuccessView() .setVisibility(View.VISIBLE); layout.getFailureView() .setVisibility(View.GONE); } }, ... }; abstract void change(StatefulFrameLayout layout); } 抽象メソッド化して サブクラスに実装を強制
  • 62. public enum State { LOADING { @Override void change(StatefulFrameLayout layout) { layout.getLoadingView() .setVisibility(View.VISIBLE); layout.getSuccessView() .setVisibility(View.GONE); layout.getFailureView() .setVisibility(View.GONE); } }, SUCCESS { @Override void change(StatefulFrameLayout layout) { layout.getLoadingView() .setVisibility(View.GONE); layout.getSuccessView() .setVisibility(View.VISIBLE); layout.getFailureView() .setVisibility(View.GONE); } }, ... }; abstract void change(StatefulFrameLayout layout); } 実際の処理は サブクラスや列挙型で実装
  • 63. public enum State { LOADING { @Override void change(StatefulFrameLayout layout) { layout.getLoadingView() .setVisibility(View.VISIBLE); layout.getSuccessView() .setVisibility(View.GONE); layout.getFailureView() .setVisibility(View.GONE); } }, SUCCESS { @Override void change(StatefulFrameLayout layout) { layout.getLoadingView() .setVisibility(View.GONE); layout.getSuccessView() .setVisibility(View.VISIBLE); layout.getFailureView() .setVisibility(View.GONE); } }, ... }; abstract void change(StatefulFrameLayout layout); } 状態ごとに サブクラスや列挙型を定義
  • 64. public void changeState(State state) { state.change(this); } 自身をパラメータとして メソッドを呼び出す