2017-04-14 6 views
1

パラメータ私は、これらはJavaクラスです、私は簡潔にするためScalaの構文を使用します(ちょっと、このようになりますように、いくつかのJava APIと統合しています:推測するタイプが

class AbstractFooBuilder[ActualType <: AbstractFooBuilder, WhatToBuild <: Foo] { 
    // ... 
    def withFoo(f: Foo): ActualType 
    def withBar(b: Bar): ActualType 
    // ... 
    def build: WhatToBuild   
} 

class FooBarBuilder extends AbstractFooBuilder[FooBarBuilder, FooBar] 
class FooBazBuilder extends AbstractFooBuilder[FooBazBuilder, FooBaz] 
// .. etc 

これらの束があり、そして私はこのような何かを持つこれらのFOOSの作成は以下の繰り返しにしようとしています:

def anyFoo[T <: Foo, B <: AbstractFooBuilder[B, T] : Manifest](foo: Foo, b: Bar) = manifest 
    .runtimeClass 
    .newInstance 
    .withFoo(foo) 
    .withBar(bar) 
    .build 

問題は今、FooBarを作成するために、私はこのような何かを書かなければならないということ、である:

val foobar = new anyFoo[FooBar, FooBarBuilder](foo, bar) 

これは私が望むよりも長いです。具体的には、一度FooBarBuilder型のパラメータがわかったら、FooBarは2番目のパラメータの唯一の可能性です...私は欠けているトリックがあるかと思います。それは他のパラメータを "推測"できるようにします。 1。

アイデア?

答えて

1

BTに依存するため、ここでは動作しません型パラメータを分割するための標準的なトリックのような何かを行うことができます。

しかしManifestを取り除くと

def anyFoo[T <: Foo](builder: AbstractFooBuilder[_, T])(foo: Foo, b: Bar) = 
    builder.withBar(b).withFoo(foo).build 

に簡素化し得ることについて何?あなたはanyFoo(new FooBarBuilder)(foo, b)と呼ぶので、Tが推測され、問題が解決されます。また、ボーナスとして、クラスがデフォルトのコンストラクターを持たない場合は、実行速度が向上し、ランタイムエラーも発生しません。

メソッドでビルダーを作成する必要がない場合は、by-nameパラメーターまたは() => AbstractFooBuilder[_, T]を使用できます。

EDIT:コメントを考えると、これは仕事ができる:

def mkBuilder[B <: AbstractFooBuilder[B, _] : Manifest]: B = // the complex creation code 

anyFoo(mkBuilder[FooBarBuilder])(foo, b) // infers FooBar 

質問はあなたがTにアクセスせずmkBuilderを実装することができるかどうかですが、元のコードはManifest[T]を必要としないならば、それは可能なはず。

あるいは

implicit class AnyFoo[T, B <: AbstractFooBuilder[B, T]](builder: B) { 
    def apply(foo: Foo, b: Bar) = builder.withBar(b).withFoo(foo).build 
} 

mkBuilder[FooBarBuilder](foo, b) 
+0

ええ、それは私がやったことです...ビルダー自体を作成するのは現実には面倒です。私は質問でそれを簡略化しただけではなく、新しいビルダーです。私は呼び出し側がどこでもそれをする必要はありません。ああ... ... – Dima

+0

編集を参照してください。あなたの問題を解決しますか? –

+0

うん、それは動作します...'anyFoo [Foo、FooBarBuilder](foo、b)'よりもはるかに短くはありませんが、醜いものではありません:) – Dima

0

私は正しくコードを読んでいます。このコードは、このタイプのファクトリが1つしかないことを意味するものではなく、使用するファクトリを指定するためにコール元に委ねられています。あなたが暗黙的に使用できる場合は

、あなたは残念ながら、この

def anyFoo[T <: Foo](foo: Foo, b: Bar)(implicit factory: AbstractFooBuilder[T]): T = { 
     factory. 
      withBar(b). 
      withFoo(foo). 
      build 
} 
+0

はい、呼び出し側が工場を指定する必要がありますが、それが構築していること、オブジェクトの型を指定する必要が_also_回避することが可能でなければなりませんようにそれがあるので、それは、感じています工場タイプによって決定される。 – Dima