クーパーで長野〜群馬〜山梨〜静岡を走った

2泊3日で走ってきました。今回は関東に住む友人のクーパーSとツーリング。

1日目

とりあえず集合場所は諏訪湖付近とし、僕は早朝に出発。名神と中央道使ってひたすら長野を目指しました。

Starbucksあるサービスエリアで休憩している写真。ボンネットの上にコーヒー乗ってます。
渋滞も事故もなくスムーズに合流ポイントに向かうことが出来ました。

合流してからは県道40号を利用して一気に霧ヶ峰方面を目指します。

地図で見ると狭そうですが、意外と走りやすくおすすめです。グニャグニャとしてるのでドライビングが楽しい。

一気に駆け上がって..

高原に入って「霧の駅」に到着。

霧の駅周辺


ギリギリ晴れてる!!


二台並べてパシャリ。どちらもF56クーパーSです。ただし僕のはATで友人のはMT。ドライビングを楽しむならやはりMTですね。


まさに高原といった風景。


なんか飛んでます。風立ちぬっぽいです。


馬もいます。

少し散歩した後、ここから美ヶ原の方へ向かいます。

とにかく高原を走りまくる。

三峰大展望台

美ヶ原方面へ向かう途中にあった展望台です。駐車場が少なくタイミングによっては入れないかもしれませんが、その分景色はかなり良いです。


小さな丘に登って当たりを見渡せるようになっています。


京都にもほしいなあこういうとこ。

ここから上田の方に向かいます。

道の駅 美ヶ原高原美術館


標高2000mにある道の駅です。道の駅ですがメインは美術館のようです。


再び二台並べてパシャリ。


ここでは上田の町を見渡すことができます。段丘の上に広がる独特の町並みが見て取れます。


2000m地点で食べるソフトクリーム。

この後は464号線から四万温泉の方へひたすら向かい、宿でのんびりして一日を終えました。

2日目

7時ぐらいに目が冷めて、直ちに朝食を済ませ、一年前は雨で何も見えず悔しい思いをした鬼押ハイウェイへ向かいます。


早朝のワインディング。朝のワインディングは本当に気持ちがよくて素晴らしい。窓も開けて気分爽快です。


道の駅で休憩。

この後、駐車場を出ようとするといきなり車内から



「ビィイィィイィイイ!!」



という謎の音が!!なんだこれ!?と焦りつつ車内や車外を見渡してもなにも異常は見られず。すぐ鳴り止んだのでしょうがなくそのまま走り出しました。







数分後、メーターの上にキリギリスが現れました。音の犯人はこいつなのでした。

鬼押ハイウェイ

涙を流した去年のハイウェイ。今年はどうか....!


晴れてる!!


鬼押出し園で駐車。浅間山も見える!!


ポケモンGOブームの波はこんなところにも。


浅間山の全貌。


今年もこの門をくぐり...


寺に向かって歩いていきます。


意味ありげな一本松。


浅間山をバックに一枚。

この後は軽井沢のアウトレットでブラブラしたり

アウトレットで買ったカレーパン。

パンの中にはカレーと鶏肉が入ってます。

八ヶ岳の近辺を走ったりしてました。

その後下部温泉に向かい更に一泊。

3日目

この日は基本的には高速を走って帰るのみですが、ちょっとだけ富士山を見ておくことにしました。

本栖湖


ここから富士山の裏側が見えます。平日なので誰もいません。


雄大!!


雲がかかってるが見えるぞ!


思わずクーパーと記念撮影。

ここからもうちょっと行ったところにも撮影できるスポットがあって、

窓から富士山を眺めることができました。

この後は新東名と新名神を駆使しして家に帰りました。三日間で1200kmぐらい走ったかと思います。やはり長野は面白い。高原が気持ち良すぎる。関西には高原が殆どないので羨ましい限りです。

次は何処に行こうかなあ。

※ 去年の涙をのんだ雨天ツーリングの様子はこちらをご覧ください。
funnelbit.hatenablog.com
funnelbit.hatenablog.com

クーパーで「京都美山 かやぶきの里」にいった

今日こそは家でのんびりしょうと思っていたのですが、外が晴れてきてどうしても我慢できなくなり、プチドライブに行ってきました。

目指したのは京都南丹にある「かやぶきの里」。ざっくりいうと白川郷の京都版、ということになるのでしょうか。

市内を抜けると時間がかかりすぎるので、京都縦貫道を園部まで北上し、そこから県道19号→県道38号を使ってアクセスします。

場所は「道の駅 美山ふれあい広場」からかなり近いです。京都のバイク乗りであれば説明不要ですよね。

かやぶきの里直ぐ側に駐車場があってクーパーはそこに停めてあります。

青い空!!本日梅雨明けが発表されましたね。嬉しい限り。


やって来ましたかやぶきの里。


広がる田んぼと山々。


集落には入る事ができます。記念資料館になっている茅葺き屋根の建物もあります。


日当たりの良い屋根には苔がたくさん生えてますね。


夏のこういう道、良いですよね。共感してくれる人いるかな。


何故か気になった、朽ち果てようとしている消火栓の標識。


屋根の上は新たな命の礎となっています。


こういうところには十中八九、美しい川がある印象です。入って遊ぶこともできるようですね。


綺麗すぎる!!


自然と共存している様が美しいですね。

帰りはちょっと美山ふれあい広場によってみたのですが人がいっぱい。

多すぎて隅っこの方に止める。

ソフトクリーム食べたかったのですが長蛇の列ができていたので諦めました。いそいそと帰路について、京都縦貫道を使って一気に帰宅しました。

この日は大体200kmぐらい。高速使えば楽ちんですね。

今年の夏は色々行きたい!次はどこに行こうかな。

電車で丹波篠山に行った

ほとんど地酒を目的として丹波篠山に行ってきました。お酒を呑むということで電車です。

京都の下のほうから出発ですので大阪まで出た後、篠山口行き(終点です)に乗って到達しました。


Dente di Leone in

到着は12時頃でしたのでまずは腹ごしらえ。
tabelog.com



こんなところにイタリアンのお店があるのは面白いですよね。料理もおいしかったですよ。

王地山稲荷神社

またの名をまけきらい神社というこの神社は、かつてどうしても他藩に相撲で勝てない篠山藩のために、稲荷の神が篠山藩のために力士に化け、勝利したということから「勝利の神」とされているようです。

稲荷はその性質から様々な「利益をもたらしてくれる神」となり易いのですが、勝利の神というのはなかなかに珍しいのではないでしょうか。


なかなかの数の鳥居が奉納されています。


おお〜おもしろい!


すぐに本殿に到達しました。なかなか立派。


切り株の上に社が建てられていて面白い。

河原町妻入商家群

かつての城下町の町並みを残した通りになります。今も人が住まれている建物が多いですね。

大正感ある電灯がちょっと不思議かも。

篠山城大書院

篠山城内にある巨大な木造建築物です。かつては藩の公式行事などに使用されたのだとか。
ちなみにこの建造物は一度火事にあって消失しているため、現在あるものは復元されたものです。
内部は見学可能です(400円)。

肝心の篠山城ですが、今は取り壊され、間取りごとに区分けされた広場が残るのみとなっています。
このお城、譜代大名(徳川方の大名)のお城で一国一城令でも取り壊されもせずにいたのですが、明治になって城が国のものとなり売り飛ばされた結果、取り壊され、今の有様になってしまったようです。

丹波栗菓匠 大福堂

和菓子屋さんです。1階が販売店、二階にほんのすこしですが茶席が設けられています。

黒豆わらび餅を注文してみました。すこしコリコリ感というか、硬めの食感で面白い。あとこの黒豆、めちゃくちゃうまいです。この豆だけほしいくらい。

ほろ酔い城下蔵

鳳鳴酒造の蔵設備見学施設です。出入り口は小売店になっていて、お酒の販売と試飲がなされています。

ちなみにこの建物は重要文化財です。


これまで酒造りで使われていた道具が並んでいます。



いい雰囲気ですね。


更に奥へと続いています。どこからかクラシック音楽が聞こえてきます。


酒樽が並んでいます。


鳳鳴酒造のお酒がズラリ。


おお!!麹室!!!


中は天井が低く暑いです。今は照明がありますが、本来なら光も一切ない空間です。


30度はすごいですね...このもやしをふりかける工程は非常に重要で、杜氏にしかできないはずです。


これ、スピーカー付いてますよね。これは一体?


おわかりでしょうか。つまり音楽を聴かせることで、酒の質が変わるというのです(マジか!?)。さっきから鳴っていたクラシック音楽はこれなのでした。

出入り口では試飲コーナがあったのでありがたくいただきました。

無料試飲と有料試飲があります。無料の方を頂いた後に有料試飲を行いました。吟醸セットで税込み518円だったかと思います。

全体的にコクが控えめで最後は辛味でキレるお酒です。飛騨高山の酒質とそこそこ似てます。山車をもうちょい飲みやすくした感じですかね。関心したのが有料試飲で飲んだ大吟醸の味わいで、後味がまるで消えるように無くなっていくお酒でした。ほんのちょっぴり辛味を感じれますが、ほとんど魔法のように消えていく。これは面白いなあと思いました。

あともう一つ面白かったのが例の「音楽振動醸造装置」で作られた酒。本当にこんなので味変わるのかよ、植物に話しかけたら伸びるみたいな奴じゃないんかいな、と半信半疑だったのですが、実際に効果を確認するために片方が音楽を聴かせている方、もう片方が聴かせてない方で試飲させていただきました。すると本当に味が違ってて、音楽有りの方はなしの方に比べると角が取れたようにまろやかで、すこしコクがあるようにも感じました。よもやこんな酒造りの方法があるとは...。

この製法で一番美味しくなる曲は何なんでしょうね?気になります。

春日神

入り口は小さめですが中は結構広い神社。本殿は小さな山を登ったところにあります。

ところでこの神社にあった黒い神馬の絵なのですが、この絵すごいなと。ちょっと写真ではわかりにくいかもしれませんがぜひ拡大して見てください。

まるで見ているものが吸い込まれてしまうようで、それでいて浮き出ているようにも見えるような黒さと、生きているような目、そしてシンプルながらも躍動感を感じさせる構図が凄まじい「生き物」感をかもし出していて、まるで絵から出てきても納得してしまうような、ゾクリとした畏れのような感覚を覚えます。

実際、この絵から黒神馬が飛び出して悪さをしてきたため金網を張ったという伝説も残っているということで、多くの人が同じように感じられてたのかと思います。

本当に凄い絵だと思います。野外展示のために痛みが結構激しそうですが、大丈夫なのかな。

ちなみに出てきて何してたかって言うと畑の豆食い荒らしていたそうです。どんだけ豆食いたいんや。

丹波篠山 郷土料理 懐

真夏ですがエアコンめっちゃ効いてたのでぼたん鍋を食べることにしました。

tabelog.com

イノシシ肉はしっかりと火を通さなければなりませんので、強火で色が完全に変わるまで待ちます。

この鍋のイノシシ肉は獣臭さが全く無く、とても食べやすいです。あと味噌も良く出来てて濃いすぎずしょっぱすぎずに調度良い。無限に御飯食べれるような味わいでした。



丹波篠山はド派手な観光地ではなく、観光もできる田舎という感じです。とてものんびりとしており、都会の喧騒をはなれてどこか行きたいなあという人に向いてるのではと思います。多分アクセスは車のほうが電車よりも良いです。電車だと駅から更にバス(本数はあまりない)ですし、電車も三田を過ぎた当たりから各駅に止まり始めるので、高速使って車で来たほうが早いのではと思います。

さて次はどこに行こうかな。

クーパーでメタセコイア並木に行った

存在は知っていながらも、なぜかこれまで一度も行ったことがなかった滋賀県高島市にあるメタセコイア並木。軽いドライブをしたかったので行ってきました。

ルートは特にひねらずに湖西道路をひたすら走って行きました。


ついに来たぞメタセコイア並木!半年ぶりぐらいに起動した一眼レフで撮りまくります。


いい意味で日本では無いみたい。


周りはごく普通の田んぼと山ですね。

このまま直帰りするのも何なので琵琶湖もちょっと見ました。


広い。


波も着てるし、パッと見は海にしか見えないですね。

白鬚神社も行こうと思いましたが駐車場が車で一杯でやめました。まあ行ったことあるから良いか。

次はどこに行こうかな。

「雪の茅舎 純米吟醸 美酒の設計 生酒」を飲んだ

酒屋でなんとなしに冷蔵庫を見てたら発見したこのお酒。


なんといっても目を引くのが「美酒の設計」という誇らしげな文字。「秘蔵」とか「幻」とか、そういう謳い文句はスルーする事が多いのですが、そんな安直なネーミングではないことと、なによりも雪の茅舎という有名銘柄がそんな文言を載せているものだから、これは試してみなければと思い、すぐさま購入してしまいました。

このお酒には特等の山田錦が使用されており、誇らしげに掲げられています。肉にもA5だとかランクがありますが山田錦にもそんなものがあり、これは上から2番目の品質を誇る山田錦ですね。

いたずらに50%まで削って大吟醸としてないあたりも、このお酒のこだわりを感じます。

さて、まず香りですがいわゆる最近流行りの吟醸香がしっかりしていますが、少し抑えめで美しい香りがします。大人しく、クリアな印象です。
飲んでみると香りから予想した通りの吟醸酒の味をまず感じますが、ほのかな青リンゴのような旨味が少し控えめに感じます。そしてしばし待つとピリッとした辛味を少し感じて辛味が顔を出し、キレていきます。この辛味はその後も結構舌の上に残り続けますね。

この控えめさとちょっとしつこめの辛さが「あれ?どんな味だったっけ?」を引き起こし、その度に一杯、また一杯と杯が進んでしまいます。

このお酒はいわゆる優等生な性質ですがそれにとどまらず、更にその先、品の良さを併せ持っており、これがこのお酒をワンランク上に感じさせる大きな特徴となっています。

さて、せっかくの宅飲みなので燗酒も試します。燗酒にするとはやりの味わい、特に青リンゴのような風味は息を潜めますが、上品さは継続してあります。辛味がほとんど無くなり、米の旨味がとろみのような味わいを見せるようになり、非常に上品な燗酒となります。ちょいと高めの温度でも大丈夫。控えめな性質は継続してあるので、グイッと飲むのが旨味をつかむコツです。


この燗酒、品が良く、後味がスッと溶けるように消えていく。これはかなりすごい。こんなに品のいい燗酒はこれまで飲んだことがないですね。まあ正直、このお酒を燗酒にしたいという人は少ないでしょう。蔵元ですらやめてくれと言うかも知れません。しかし僕はこのお酒の燗には大きなポテンシャルがあると感じます。

誤解されないように申し上げておくと全部燗にして飲みたいわけではないです。キリッと冷やしても、燗にしてもどちらもうまい。どちらの温度にしてもしっかりと設計された「美酒」の根底は揺らがない。そんな懐の深い酒だなあと感じました。

ごちそうさまでした。

Dagger2のProducers 基本的な使い方

square 社製の Dagger を fork して生まれた Dagger2(Google Dagger) は、リリース当初は導入事例があまり見られず手探りな状態が続いていましたが、最近ではプロダクトへの導入事例を聞くことも珍しくなくなりました。僕が関わっているいくつかのプロダクトでも Dagger2 を積極的に利用しており、もはやなくてはならない存在になったと言っても過言ではありません。

ところで、 Dagger2 は形式に沿った Module と Component のコードを書くことで、コンパイル時に依存注入するためのコードを生成し、アプリケーションが依存注入を要求した時に処理を実行するものです。この処理は同期的に行われますが、もしこの処理自体を非同期にしたい場合はどうすればよいのでしょうか。例えば、APIを叩くなどの処理が絡んでしまい、同期的に依存を解決できない場合。また依存解決に必要な処理をどうしてもメインスレッドで待つことが出来ない場合や、パフォーマンスの関係上非同期のほうが都合が良い、などといった場面の場合。我々エンジニアは、どのような書き方をすべきなのでしょうか。

その答えは既に Dagger2 に用意されています。Producers という仕組みを利用するのです。

目次

はじめに

Dagger2 には Producers という非同期で依存を解決する仕組みがあります。

通常の Inject とは違い、@Inject アノテーションを使うことはありません。 Component は ListenableFuture<T> を返すメソッドを定義するようにし、 <T> を注入して欲しいクラスはそのメソッドを呼び出します。そして非同期にインスタンスを受け取るのです。

基本的な使い方

    // dagger2
    compile 'com.google.dagger:dagger:2.5'
    compile 'com.google.dagger:dagger-producers:2.5' // これが必要
    apt 'com.google.dagger:dagger-compiler:2.5'
    androidTestApt 'com.google.dagger:dagger-compiler:2.5'
    provided 'javax.annotation:jsr250-api:1.0'

build.gradle で producers を追加する

Producers は Dagger2 を拡張したものですので、追加の dagger-producers を読み込んでおく必要があります。

簡単な例です。 String を返す Module を考えてみます。記述のポイントは以下のとおりです。

  • @ProducerModule を使うことになります。
  • userName(UserData userData) が注入するインスタンスを返すメソッドです。
  • provideUserData()UserData を生成して返しますが、そのまま返すのではなく、 ListenableFuture<UserData> を返すようにします。

@ProducerModule
final class AppProducerModule {
    @Produces
    ListenableFuture<UserData> provideUserData() {
        // ~ なんかめっちゃ時間がかかる処理 ~
        return Futures.immediateFuture(new UserData("userName"));
    }

    @Produces
    String userName(UserData userData) {
        return userData.name;
    }
}

時間がかかる処理があると仮定した AppProducerModule.java

実は Module がもう一つ必要で、それが以下に示す Executor を返す Module です。

@Module
public class ExecutorModule {
    @Provides
    @Production
    static Executor executor() {
        return Executors.newCachedThreadPool();
    }
}

ExecutorModule.java

この Executor は、非同期で依存を解決する Executor を提供するものです。

次に Component ですが、 @ProductionComponent を使います。

@ProductionComponent(modules = {ExecutorModule.class, AppProducerModule.class})
    public interface AppProducerComponent {
        ListenableFuture<String> userName();
    }

非同期依存注入で利用する AppProducerComponent.java

ExecutorModule.class はここで指定しています。

返り値が ListenableFuture<UserData> となっている点に注意してください。

注入して欲しいクラス、例えば Activity は、この Component のメソッドからインスタンスを受け取ります。

public class MainActivity extends AppCompatActivity {
    ...
        ListenableFuture<String> userDataListenableFuture = DaggerAppProducerComponent.create().userName();
        Futures.addCallback(userDataListenableFuture, new FutureCallback<String>() {
            @Override
            public void onSuccess(String result) {
                Log.e("name", result);
            }

            @Override
            public void onFailure(Throwable t) {

            }
        });
    ...
}

結果を受け取る MainActivity.java

これを実行した時、 AppProducerModule では順番にメソッドが呼ばれ、依存解決を試みます。

@ProducerModule
final class AppProducerModule {
    @Produces
    ListenableFuture<UserData> provideUserData() {
        // 1. まずはじめにここが呼ばれる。
        return Futures.immediateFuture(new UserData("userName"));
    }

    @Produces
    String userName(UserData userData) { // 1 で解決されるインスタンスが必要
        // 2. 1が終わったらここが呼ばれる。
        return userData.name;
    }

}

AppProducerModule.java 内の処理の流れ

Module は includes を使うことによって、他の Module と関係をもつことも出来ます。

@ProducerModule(includes = UserDataRequestModule.class)
final class AppProducerModule {
    @Produces
    ListenableFuture<UserData> provideUserData(APIClient client) {
        return Futures.immediateFuture(client.get()));
    }

    @Produces
    String userName(UserData userData) {
        return userData.name;
    }

}

UserDataRequestModule.class を includes する

UserDataRequestModule.classAPIClient をくれる、というイメージです。

生成されたコードでExecutorはどう使われるか

処理はすべて非同期で、 Executor を用いて行われます。先ほど ExecutorModule クラスで Executor を返すメソッドを定義しましたが、この Executor は一体どのように扱われているのでしょうか。 生成されたコードを見てみると、その答えがわかります。

public final class DaggerAppComponent implements AppComponent {
  private Provider<Executor> executorProvider;
  ...
    this.executorProvider =
        DoubleCheck.provider(
            AppComponent_ProductionExecutorModule_ExecutorFactory.create(
                ExecutorModule_ExecutorFactory.create()));
  ...

生成された DaggerAppComponent.java

Executor は Dagger によって生成されたコードの中で、 Provider<Executor> として保持されます。 この Provider はそれぞれの Factory クラス内でコンストラクタ経由で渡され、

public final class DaggerAppComponent implements AppComponent {
...
    this.getUserDataProducer =
        new AppProducerModule_GetUserDataFactory(
            builder.appProducerModule, executorProvider, monitorProvider);
...

UserData を 供給する Producer を作る AppProducerModule_GetUserDataFactory() で渡されている

Factory クラスが compute() メソッドによって処理を始めた時、 Futures の transformAsync() メソッドで非同期処理を行うときに get() メソッドを呼ぶことで Executor を得ています。

public final class AppProducerModule_GetUserDataFactory extends AbstractProducer<UserData> {
  ...
    @Override
  protected ListenableFuture<UserData> compute(final ProducerMonitor monitor) {
    return Futures.transformAsync(
        Futures.<Void>immediateFuture(null),
        new AsyncFunction<Void, UserData>() {

          @Override
          public ListenableFuture<UserData> apply(Void ignoredVoidArg) {
            monitor.methodStarting();
            try {
              return AppProducerModule_GetUserDataFactory.this.module.getUserData();
            } finally {
              monitor.methodFinished();
            }
          }
        },
        executorProvider.get());
  }

Dagger によって生成された AppProducerModule_GetUserDataFactory.java

補助的な機能

Dagger2には、様々な非同期の依存解決を実現する機能が用意されています。

Producer

先程も登場した Provider<T> と似た仕組みが Producers には用意されています。それが Producer<T> です。

まずは Module ですが、いわゆる出口であるメソッド以外で特に変わることはありません。

    @Produces
    @Normal
    ListenableFuture<UserData> provideNUserDate() {
        return Futures.immediateFuture(new UserData("normal"));
    }

    @Produces
    @Special
    ListenableFuture<UserData> provideSUserDate() {
        return Futures.immediateFuture(new UserData("special"));
    }

    @Produces
    ListenableFuture<UserData> provideUserData(@Normal Producer<UserData> nProducer, @Special Producer<UserData> sProducer) {
        return sProducer.get();
    }

Producer を受け取る provideUserData() が定義されている AppProducerModule.java

受け取り側は、インスタンスそのものを受け取る or Producer を受け取るかを決定する権利を持っています。この点は Provider<T> の性質と全く同じです。 これによって provideUserData(...) は、何かしらの処理によって依存解決処理そのものを決定できる権利を持つのです。 例えば、 Dagger2 のドキュメントの例には Flag を見て処理を分けています。

Component も、そのメソッドを使う注入先の記述も何も変わりません。手を入れるのは Module だけです。

Produced

以下の Module のコードを見てください。確実に例外が発生するコードです。

@ProducerModule
final class AppProducerModule {
    @Produces
    ListenableFuture<UserData> getUserData() {
        // ~ なんかめっちゃ時間がかかる処理 ~
        throw new IllegalStateException(); // わざと落とす
        //return Futures.immediateFuture(new UserData("userName"));
    }

    @Produces
    String userName(UserData userData) {
        return userData.name;
    }
}

例外が起こって UserData を return できない AppProducerModule.java

この時、Dagger は依存の解決を諦め、スキップを行います。これは Module 内で何か都合の悪い予期せぬ自体が起きた時、例外が起きてクラッシュするのを防ぐためであると思われます。 ただ、例外を自らの手でハンドリングしたいことも有ります。その場合は Produced<T> を使うことで実現できます。

@ProducerModule
final class AppProducerModule {
    @Produces
    ListenableFuture<UserData> getUserData() {
        // ~ なんかめっちゃ時間がかかる処理 ~
        throw new IllegalStateException(); // わざと落とす
        //return Futures.immediateFuture(new UserData("userName"));
    }

    @Produces
    String userName(Produced<UserData> userData) {
        try {
            return userData.get().name;
        } catch (ExecutionException e) {
            e.printStackTrace();
            return "何かが起きた";
        }
    }
}

必ず "何かが起きた" を返す AppProducerModule.java

スタックトレースが吐かれ、"何かが起きた"が返されます。

@IntoSet

複数のインスタンスSet<T> に保持し、依存を解決する仕組みがあります。それが @IntoSet です。 Module のメソッドに付与することで機能します。以下の例を御覧ください。

public class AppProducerMultiBindingsModule {
    @Produces
    @IntoSet
    ListenableFuture<UserData> provideNUserDate() {
        return Futures.immediateFuture(new UserData("normal"));
    }

    @Produces
    @IntoSet
    ListenableFuture<UserData> provideSUserDate() {
        return Futures.immediateFuture(new UserData("special"));
    }

    @Produces
    @IntoSet
    UserData provideDogUserDate() {
        return new UserData("dog");
    }
}

@IntoSet を付与したメソッドを定義した AppProducerMultiBindingsModule.java

Component はこのようにします。

@ProductionComponent(modules = {ExecutorModule.class, AppProducerMultiBindingsModule.class})
public interface AppProducerMultiBindingsComponent {
    ListenableFuture<Set<UserData>> getSet();
}

ListenableFuture<Set> を返すメソッドを定義した AppProducerMultiBindingsComponent.java

getSet() が呼ばれた時、関連するすべての依存の解決が試みられます。例えば上の Module の例では、すべての provide~ メソッドが、getSet() された瞬間に呼ばれるということです。インスタンスが生成され次第、Set<t> の中に追加されていきます。

ListenableFuture<Set<UserData>> set = ((App) getApplication()).getAppProducerMultiBindingsComponent().getSet();
        Futures.addCallback(set, new FutureCallback<Set<UserData>>() {
            @Override
            public void onSuccess(Set<UserData> result) {
                Log.e("success", String.valueOf(result.size())); // 3
            }

            @Override
            public void onFailure(Throwable t) {
                Log.e("error", t.toString());
            }
        });

結果を Log.e(...) で出力する MainActivity.java

すべての処理が終わり次第、 onSuccess() が呼ばれる、ということになります。

Module 内でこの Set<T> を利用して新たな値を返す技もあります。以下の例では(意味不明ですが)すべての UserData の名前を合体させて、新しい UserData を返しています。

@ProducerModule
public class AppProducerMultiBindingsModule {
    @Produces
    @IntoSet
    ListenableFuture<UserData> provideNUserDate() {
        return Futures.immediateFuture(new UserData("normal"));
    }

    @Produces
    @IntoSet
    ListenableFuture<UserData> provideSUserDate() {
        return Futures.immediateFuture(new UserData("special"));
    }

    @Produces
    @IntoSet
    UserData provideDUserDate() {
        return new UserData("dog");
    }

    @Produces UserData collect(Set<UserData> data) {
        Iterator<UserData> i = data.iterator();

        UserData normal = i.next();
        UserData special = i.next();
        UserData dog = i.next();

        return new UserData(normal.name + " and " + special.name + " and " + dog.name);
    }
}

collect() ですべての UserData.name を 足しあわせて返す AppProducerMultiBindingsModule.java

@ElementsIntoSet

Set<T> は Dagger で生成されたコードによって作られますが、 @ElementsIntoSet を使えば、複数の値を Set<T> に入れておくメソッドを自分で書くことも出来ます。

@ProducerModule
public class AppProducerMultiBindingsModule {
    @Produces
    @IntoSet
    ListenableFuture<UserData> provideNUserDate() {
        return Futures.immediateFuture(new UserData("normal"));
    }

    @Produces
    @IntoSet
    ListenableFuture<UserData> provideSUserDate() {
        return Futures.immediateFuture(new UserData("special"));
    }

    @Produces
    @IntoSet
    UserData provideDUserDate() {
        return new UserData("dog");
    }

    @Produces
    @ElementsIntoSet
    ListenableFuture<Set<UserData>> provideSet() {
        return Futures.<Set<UserData>>immediateFuture(ImmutableSet.of(new UserData("foo1")));
    }

    @Produces UserData collect(Set<UserData> data) {
        Iterator<UserData> i = data.iterator();

        UserData normal = i.next();
        UserData special = i.next();
        UserData dog = i.next();
        UserData foo1 = i.next(); // @ElementsIntoSet

        return new UserData(normal.name + " and " + special.name + " and " + dog.name);
    }
}

@ElementsIntoSet を付与した provideSet() を定義した AppProducerMultiBindingsModule.java

@IntoMap

Set<T> だけでなく Map<K, V> で扱うことも出来ます。

@MapKey
@interface Type {
    String value();
}

@ProducerModule
public class AppModule {
    @Produces
    @IntoMap
    @Type("cat")
    static ListenableFuture<UserData> cat() {
        return Futures.immediateFuture(new UserData("cat")); // このコードでは呼ばれない
    }

    @Produces
    @IntoMap
    @Type("dog")
    static ListenableFuture<UserData> dog() {
        return Futures.immediateFuture(new UserData("dog")); // このコードでは呼ばれない
    }

    @Produces
    ListenableFuture<Integer> size(Map<String, Producer<UserData>> map) {
        return Futures.immediateFuture(map.size()); // 2
    }
}

@IntoMap を使い、生成されたMapを使って Integer を返す AppModule.java

この例はすべての UserData の合計値を出しているものですが、UserData そのものを受け取っていません。受け取っているのは Producer<UserData> であり、単に map の size を得ているだけです。そのため、 cat() メソッドと dog() メソッドを動かすこと無くサイズを得ています。

まとめ

Producers を使えば、記事冒頭に書いたような要件をすべてクリアできるはずです。ちなみに Module 内のメソッドが一つ一つ非同期に流れていくさまはすこし RxJava ようではありますが、この仕組みはあくまでも非同期な依存注入を実現するためのものです。 RxJava と競合する仕組みでは勿論ありませんし、むしろ組み合わせて使うことでより利便性が向上するものであると理解しています。

効果的に使うことで大きな利益をもたらすと思われますが、まだ実際にプロダクトに導入もしておらず、僕自身も未だ深くは理解できていません。

もう少し遊んでみて、確実に効果の出せる箇所がありそうなら使っていきたいなと思っています。

より深い理解を望む場合は、Dagger2 の公式ドキュメントを御覧ください。 google.github.io

博多行って食べたもの

先週木曜ぐらいに「今週末暇だな。そういや博多行きたいんだった」と唐突に思いつき、土日使って博多に行ってきました。

 

tabelog.com

ラーメン。麺がすごく細い。ここまで細いのは珍しいようで。麺は硬めにしました。まあ分かってたけど、美味い...

 

ラーメン屋はもう一軒行きました。

tabelog.com

こちらは「豚骨ハイブリッド味玉ラーメン」。いや〜文句無しに美味い。あとここのお店に置いてあった辛子高菜も美味い!辛すぎて舌がヒリヒリしますけどね。辛いのが苦手な方は慎重になったほうがよさそう。

 

夜は飲み屋ですごしてました。

 ゴマ鯖。ゴマ鯖って知ってますか?僕は知りませんでした。「ゴマ鯖知らんのか!?」と地元民に驚かれてしまいました。どうやら博多の郷土料理のようですね。

胡麻鯖 - Wikipedia

新鮮な生の鯖にこの甘めのタレがよく合う。ここに福岡県八女市の地酒である「喜多屋」の純米大吟醸をあわせます。

 

甘みと辛味が同居している酒ですが甘みのほうが派手さがあるのでぱっと飲んだ時の印象は甘めの酒。この甘さがゴマ鯖の甘めのタレとよく合います。

www.kitaya.co.jp

 

鯵の活造り。こんなに素材の味がしっかりしている鯵は初めて食べました。長崎県からやってきたそうです。

 

かにみそとカニの身とウニを混ぜあわせた物にいくらをかけて食べるという海の旨味の塊みたいな料理。

 

ふぐの一夜干し炙り。間違いなく酒が進む一品。

 

これも福岡の地酒、天心。純米酒。酸味はちょっとしっかりめ純米酒とは思えないほど爽やか。ちょっと夏酒っぽい味だった。夕刻にひぐらしの声を聴きながら飲みたいと思える酒

 

フラフラ〜っと屋台の方にも行ってみました。一度ここで食べたかったんですよ。

 

これは間違いなくいい場所ですよね。

たことポン酢を和えたものや....

 

牛タンのステーキ。

 

手羽先の中になんと明太子を詰め込んだものも。

 

やっぱり海と山が近い街は強いですね。良い食材がいっぱいある。個人的に海が近いのが本当に羨ましい。

 

オマケにちょっとだけ観光した時の写真をどうぞ

博多はいわゆる都会な町並みなのですが、都会独特の息苦しさが全く感じられませんでした。人が少ないからなのか、建物が新しいからか、休日だったからなのか、それとも博多の人柄が街をそう見せるのか。わかりませんがここなら試しに住んでみたいなと思える街でしたね。若者もかなり多いし、未来がある面白い街だと思います。

 

次はどこに行こうかな。