Kotlinとスプラトゥーンで学ぶデザインパターン【4. Factory Method】
昨日前夜祭で久しぶりのスプラトゥーンを満喫してました。
エイムも操作もひどいことになってました。
しばらくはリハビリ期間になりそうです・・・
Factory Methodパターンとは
Factory Methodパターンは、インスタンスの作り方をスーパークラスで定め、実際にインスタンス化する処理はサブクラスに分けて実装するパターンです。
今回は、サーモンランの敵を題材にしました。登場から攻撃までの処理を実装します。
実装
まず枠組みとなるスーパークラスを2つ定義します。
Factory.kt
abstract class Factory { fun create() : Enemy { var enemy = createEnemy() deployToMap(enemy) return enemy } abstract fun createEnemy() : Enemy abstract fun deployToMap(enemy: Enemy) }
Enemy.kt
abstract class Enemy { abstract fun attack() abstract fun move() abstract fun appear() }
Factoryでは生成してからマップに配置するまでの処理を行なっています。
次に具象クラスです。バクダンという敵をインタンス化します。
BakudanFactory.kt
class BakudanFactory : Factory() { override fun createEnemy(): Enemy { return Bakudan() } override fun deployToMap(enemy: Enemy) { enemy.appear() } }
Bakudan.kt
class Bakudan : Enemy() { override fun attack() { println("爆弾を発射!") } override fun move() { println("ちょっと移動") } override fun appear() { println("バクダンが現れた!") } }
実行結果
バクダンが現れた! ちょっと移動 爆弾を発射!
Kotlinとスプラトゥーンで学ぶデザインパターン【3. Template Method】
スプラトゥーン2発売日まで1ヶ月を切りました。
E3での大会、日本チームは惜しくも2位でしたが熱い試合でした。
今回はTemplate Methodパターンです。
Template Methodパターンとは
Template Methodパターンは、親クラスで処理の枠組みを決め、子クラスで具体的な処理を記述するデザインパターンです。
スプラトゥーンでこのデザインパターンが適用できるところがなかなか見つからなかったのですが
試合結果画面がナワバリとガチで違うことに気づき今回は試合結果画面を題材にすることにしました。(前提として勝った時しか考慮していません)
実装
まずナワバリバトルとガチバトルの違いを見極めます。
<ナワバリバトル>
- 左上のポイントは塗った面積、
- チームのリザルトにはランク、武器、名前、塗った面積
<ガチバトル>
- 左上のポイントはランクに応じてランクに応じて取得できるポイント
- チームのリザルトにはランク、武器、名前、腕前
が各々表示されます。
これらのことを考慮して実装するとイカのようになりました。
GameResult.kt
abstract class GameResult { abstract fun showScore(player: Player) abstract fun showTeamResult(players: Array<Player>) fun show(players: Array<Player>) { //一人目のプレイヤーが自分自身 showScore(players[0]) showTeamResult(players) } }
スコア表示、チーム表示メソッドを抽象化して具象クラスに任せています。
Player.kt
data class Player(val name: String, val rank: Int, val udemae: String, val score:Int, val wepon:String)
データクラス。
NawabariBattleResult.kt
class NawabariBattleResult: GameResult() { override fun showScore(player: Player) { println("" + player.score + "ポイント獲得しました!") } override fun showTeamResult(players: Array<Player>) { for (player in players) { println("" + player.rank + ", " + player.wepon + ", " + player.name + ", " + player.score) } } }
GachiBattleResult.kt
class GachiBattleResult : GameResult() { override fun showScore(player: Player) { println("" + getScoreByUdemae(player.udemae) + "ポイント獲得しました!") } override fun showTeamResult(players: Array<Player>) { for (player in players) { println(player.wepon + ", " + player.name + ", " + player.rank) } } //ノックアウトは考慮しない private fun getScoreByUdemae(udemae: String): Int { when (udemae) { "C-" -> return 1000 "C" -> return 1300 "C+" -> return 1600 "B-" -> return 2000 "B" -> return 2300 "B+" -> return 2600 "A-" -> return 3000 "A" -> return 3300 "A+" -> return 3600 "S" -> return 4000 else -> return 5000 } } }
具象クラスの実装は上記のようになりました。
呼び出すときはイカのように。
println("ナワバリバトルの結果") val nawabariResult: NawabariBattleResult = NawabariBattleResult() nawabariResult.show(players) println("\n\nガチバトルの結果") val gachiResult: GachiBattleResult = GachiBattleResult() gachiResult.show(players)
ソースはこちら
github.com
Kotlinとスプラトゥーンで学ぶデザインパターン【2. Adapter】
なんとか第二回もできました!
今回はAdapterパターンです。
Adapterパターンとは
デザパタ本には
「すでに提供されているもの」と「必要なもの」の間の「ずれ」を埋めるデザインパターン
とあります。この通りなんですが、じゃあスプラトゥーンでこのパターンが使えそうな所はあるかなぁと考えました中々思いつかず。
やっと思いついたのがスプラトゥーン2のローラーの攻撃方法の変更でした。
1では横振りのみでしたが、2ではタテ振りという概念が追加されました。
この差をAdapterパターンで埋めてみることにしました。
実装
まず、1のときの実装は以下のようになっています。
val roller : SplaRoller = SplaRoller()
println(roller.swing())
ローラークラスの詳細は以下
open class SplaRoller { fun swing():String { return "Swing!" } }
出力結果
Swing!
ただ振るのみ。
次に2のローラーの実装は以下のようにメソッドを呼び出せる想定で実装します。
val newRoller : SplaRoller2 = NewSplaRoller()
println(newRoller.swingHorizontal())
println(newRoller.swingVertical())
そのために必要なものが、まずは2仕様のインターフェース
SplaRoller2.kt
interface SplaRoller2 { fun swingHorizontal(): String fun swingVertical(): String }
旧仕様と新仕様を繋ぐクラス
NewSplaRoller.kt
class NewSplaRoller : SplaRoller(), SplaRoller2 { override fun swingHorizontal(): String { return "Horizontal " + swing() } override fun swingVertical(): String { return "Vertical " + swing() } }
出力結果
Horizontal Swing! Vertical Swing!
という感じです。ちなみに縦振り・横振りは振り始めにジャンプしているか否かで判定されるようです!
実装してみて
実装パターンをパッと見た所、クラス・インターフェースが冗長な感じがしました。
元の実装をそのとき必要な実装に合わせるだけならSplaRollerクラスを継承してSplaRoller2を作るという方が簡単ではないかと。
でもよくよく考えると、単純に継承するだけだとSplaRollerクラスが変更された時に影響を受けやすい気がします。できるだけ疎結合にしておくという意味でやはり間に継承or移譲するクラスを挟んだ方が良さそうという結論に至りました。
蛇足
これは「ダイナモローラー」。
— Splatoon(スプラトゥーン) (@SplatoonJP) 2017年6月8日
振りかぶりは遅いが、広範囲にインク攻撃ができるローラータイプのブキだ。
タテ振りはかなり遠くまで届くので、これまで苦手だった遠距離の相手も牽制できそうだ。
サブは「トラップ」、スペシャルは「ハイパープレッサー」だ。 pic.twitter.com/aWOgGl2y9t
気になっていたダイナモの縦振りやはり存在するようですね。
ローラーですら相当な飛距離なのでダイナモならどんだけ飛ぶんだよ!とか楽しみにしてます。
想像では、ダイナモの縦振り=Fateのアーサー王のエクスカリバーです。
Kotlinとスプラトゥーンで学ぶデザインパターン【1. Iterator】
頭の中がごちゃごちゃ
最近自分の中で考えてることをごちゃ混ぜにしてアウトプットしたらタイトルのような結果になりました。
イカ、最近の自分の思考
- 「サーモンランとか激アツ!これはローカルでできてほしい」
- 「あかべこ本一通りやったけど次は何しよう」
- 「スプラトゥーン2発売まで2ヶ月きった!」
- 「WiiU売ってしまってスプラトゥーンできない。やりたいやりたいYoutubeで我慢」
- 「KotlinがGoogle公式の言語に!これはプロダクト採用ワンチャンある。勉強しよう」
- 「2はとりあえずチャージャーから入ってエイムリハビリしていこう」
- 「アーキテクチャ意識して制約加えてコーディングするようになってから悩む時間が増えた」
- 「制約の中でもスムーズにコーディングするためにはデザインパターン的な技が必要では?」
- 「赤木も山王工業戦に備えてスピンムーブとか練習してたし、やはり新しい技(デザインパターン)を習得しよう」
ベースになっているのは結城浩さんのデザインパターン本です。
それをKotlinで書き直してみました。第一回目はIteratorパターンです。
ソースは
DesignPatternInKotlin/src/iterator at master · kseito/DesignPatternInKotlin · GitHub
にまとまっています。
Iteratorパターン
Iteratorパターンとは、何かの集合から要素を順番に取り出して処理していくものです。
今回は、スプラトゥーンのイカの画面を意識して作りました。
バトルで使用する武器を選択する画面です。
武器(Wepon)があり、それがリスト化(WeponList)されそれが一覧表示(WeponIterator+println)されます。
Wepon.kt
data class Wepon(val name: String, val range: Int, val power: Int, val quickness: Int)
WeponList.kt
class WeponList(count: Int): Aggreagte { override fun iterator(): Iterator { return WeponIterator(this) } private var wepons: Array<Wepon?> = arrayOfNulls(count) private var count: Int = 0 fun add(wepon: Wepon) { wepons[count] = wepon count++ } fun getWeponAt(index: Int): Wepon? { return wepons[index] } fun getCount(): Int { return count } }
WeponIterator.kt
class WeponIterator(private val weponList: WeponList) : Iterator { private var index: Int = 0 override fun next(): Any { val wepon: Wepon? = weponList.getWeponAt(index) index++ return wepon ?: Wepon("未開放", 0, 0, 0) } override fun hasNext(): Boolean { return weponList.getCount() > index } }
デザインパターンとして作成するクラスはここまで(Interfaceは省略します)
あとは動かすだけ。
Main.kt
fun main(args: Array<String>) { val list: WeponList = WeponList(5) list.add(Wepon("わかばシューター", 32, 32, 75)) list.add(Wepon("スプラシューターコラボ", 50, 45, 55)) list.add(Wepon(".96ガロンデコ", 68, 85, 15)) list.add(Wepon("カーボンローラー", 20, 65, 70)) list.add(Wepon("ダイナモローラー", 72, 30, 20)) val weponSelect: Iterator = list.iterator() while (weponSelect.hasNext()) { val wepon: Wepon = weponSelect.next() as Wepon System.out.println("武器名:" + wepon.name + "、射程:" + wepon.range + "、攻撃力:" + wepon.power + "、連射力:" + wepon.quickness) } }
出力結果は
武器名:わかばシューター、射程:32、攻撃力:32、連射力:75 武器名:スプラシューターコラボ、射程:50、攻撃力:45、連射力:55 武器名:.96ガロンデコ、射程:68、攻撃力:85、連射力:15 武器名:カーボンローラー、射程:20、攻撃力:65、連射力:70 武器名:ダイナモローラー、射程:72、攻撃力:30、連射力:20
となります。
RxJava2.0の基本クラスを学ぶ
今さらですがRxJava2.0について学びたいと思います。
RxJava2.0ではObservableに似たクラスとしてFlowable, Maybeが追加されています。
今回は復習の意味も込めて、Observable, Single, Completable, Maybeの違いについて調べてみたいと思います。
Flowableはだいぶ特殊でObservableで扱うストリームでバッファを考慮するとき等に使うようで、(自分にとっては)現状あまり用途がないので割愛します。
Observable
0~N個のオブジェクトの流れ、完了、エラーを扱います。
プログラム
Observable.range(1, 10) .subscribe(System.out::println);
出力結果
1 2 3 4 5 6 7 8 9 10
Single
1つのオブジェクトの流れ、エラーを扱います。 onCompleteは呼ばれないです。
プログラム
Single.just(1)
.subscribe(System.out::println);
出力結果
1
Completable
オブジェクトの流れは扱わず、完了かエラーの判定のみ扱います。
完了
プログラム
Observable<Integer> observable = Observable.range(1, 10); Completable.fromObservable(observable) .subscribe( () -> System.out.println("Complete!"), e -> System.out.println(e.getMessage()));
出力結果
Complete!
エラー
プログラム
Completable.fromObservable(observable) .subscribe( () -> System.out.println("Complete!"), e -> System.out.println(e.getMessage()));
出力結果
damepo
Maybe
0~1個のオブジェクト、エラーを扱います。 onCompleteは呼ばれます。
プログラム
Maybe.just(1) .filter(integer -> integer == 2) .defaultIfEmpty(3) .subscribe(System.out::println);
出力結果
3
感想
SingleとMaybeの違いが分かりづらいです。 Singleに0個のオブジェクトの時の処理を追加したのがMaybeなのかな・・・。もっと勉強しないと!
参考URL
GitHub - ReactiveX/RxJava: RxJava – Reactive Extensions for the JVM – a library for composing asynchronous and event-based programs using observable sequences for the Java VM. RxJava2.0 Observable, Single, Maybe, Completableの使い分けメモ - Qiita
KalitaのネクストGを購入しました!
今回は念願のネクストGを購入したので使い心地や感想を書きたいと思います。
きっかけ
前々から今使ってるコーヒーミルの微粉の多さに悩んでましたが、次買うとしたら高性能なコーヒーミルを買いたかったので躊躇してました。
そんなとき、神乃コーヒーのコーヒーセミナーに参加して、そこで使用していたミルと挽いた豆の粒の揃い具合に驚愕しました。フジローヤルのミルを使用していたのですが、そんなに大きくないサイズでしっかり粒の揃った豆を挽けるとは・・・これは買うしかない!という流れです。
そのあとコーヒーミルの調査をして最終的にみるっこDXとネクストGが残りました。なぜネクストGにしたかと言うと完全に値段の問題です。現時点でネクストGの方が1万円くらい安かったからです。性能的にもそこまで差は見られなかったのでネクストGを購入しました。
良かった点1 雑味が減った
当然といえば当然ですが粒が揃って微粉が減ったので以前より雑味が減りました。これで新鮮なスペシャリティーコーヒーを挽いて飲んだ日にはその日1日上機嫌で過ごせそうです!
良かった点2 音が静か
以前から音はあまり気にしていなかったのですが、以前使っていたコーヒーミルよりも音が小さくなりました。ネクストGの特徴としてカッターの回転速度が遅いという情報があったのでそのおかげかもしれないです。
まとめ
結果として、ネクストGのおかげで以前より美味しいコーヒーが飲めるようになったので買って正解でした。道具をアップグレードしてより美味しいコーヒーが飲めるようになるのって、RPGに近い感じがしますね。
「成長している」という感覚を大事にしながらより美味しいコーヒーを追求していきたいと思います。
次は水出しコーヒーかなぁ。サイフォンもやってみたい。
おまけ情報
コーヒーセミナーで使ってたコーヒーポッドが良かったので紹介しておきます。
タカヒロというメーカーのコーヒーポッドを使っていたのですが、狙ったところにお湯を注げてあまりの使いやすさにセミナーの講師の方に聞きました。注ぎ口の先端部が曲線になっているのが特徴らしいです。
いつか買いたい・・・
ConnectionResult.SERVICE_VERSION_UPDATE_REQUIREDを受け取ったときに試すこと
検証端末としてHuawei MediaPad M3を購入して自作アプリとかの動作検証してたらマップ表示ができなくてはまったので備忘録として記載します。
原因
if (ConnectionResult.SUCCESS != GooglePlayServicesUtil.isGooglePlayServicesAvailable(this)) { //エラー処理 }
マップ表示前に上記のように分岐させてGoogle Play Servicesが有効かチェッックしていたんですが、ここで今回購入した端末のみConnectionResult.SERVICE_VERSION_UPDATE_REQUIREDを返却されてました。 内容としてはPlayストアを最新にしてくれってことらしいんですが既に最新版なっていました・・・。
解決策
原因はPlayストアのパーミッションでした。
端末の初回設定後、ログインした以外特に何もしていないのですがパーミッションの状態が下記のようになっていました。
位置情報がOFFになっている・・・
位置情報パーミッションをONにしてあげることで解決しました。
暫定対応策としては上記のような方法になりますが、根本対策はGooglePlayServicesUtil.isGooglePlayServicesAvailableではなく
GoogleApiAvailability.isGooglePlayServicesAvailableを使う方法らしいです。deprecatedメソッドは使わない方が良いですね。