3

私は、驚くほど多くの抽象化を備えた ubercool アプリケーションを構築中です。ここで、過度に設計された EntityGetService を設計します。

私が最初に欲しいのは、多くの抽象型です。次のように言ってみましょう:

trait EntityGetService[ID, ENTITY, CONTAINER] {
  def get(id: ID): CONTAINER
}

ここでの CONTAINER は、要求されたエンティティを含む (または含まない) 何かのタイプです。Option[ENTITY] と非常によく似ています。しかし、私が望む 2 番目のことは、CONTAINER も Future[ENTITY] にすることができることです。

だから本当に私はこのような特性を書きたいです:

trait EntityGetService[ID, ENTITY, CONTAINER <: Wrapper[ENTITY]] {
    def get(id: ID): CONTAINER
}

次のように指定します。

trait EntitySyncGetService[Long, Entity, Option[Entity]] {
    def get(id: Long): Option[Entity]
}

trait EntityAsyncGetService[Long, Entity, Future[Entity]] {
    def get(id: Long): Future[Entity]
}

Option と Future に何かを再拡張または混合せずにこれを行う方法はありますか?

Option と Future には少し共通点があるようです (両方のコンテナー)。それはモナドに関連するものですか?

それとも、これは私の不眠症の産物ですか?

4

2 に答える 2

3

すべての合理性についてコメントするのではなく、高次の型を使用できます。

trait WrappedGetService[ID, ENTITY, WRAPPER[_]] {
  def get(id: ID) : WRAPPER[ENTITY]
}

次に、を宣言できますWrappedGetService[Long, Entity, Option]

更新:いくつかの参照

この機能は、高次型(おそらく高次型も) または型コンストラクターと呼ばれます。

  • 言語仕様では、主にセクション 4.4, 型パラメータに記載されているはずですが、それについては多くはありません。他の型パラメータと同じように機能します。
  • この機能は、論文Generics of a higher kind で最初に提案されました。この論文は、言語のとおりに正確に実装されていない可能性がありますが、非常に近いはずです。一方、コレクション ライブラリは別の方向に進みました。その理由は、Fighting Bit Rot with Typesでわかるかもしれません。
  • scalazライブラリを参照してください(気弱な人向けではありません)。その通りに行くなら、Haskell も見てみたいと思うかもしれません。
于 2013-04-01T10:31:16.183 に答える
3

これは、私が「手動 AOP」と呼んでいるものを少し使用することで実現できます。

Option最初に、 、Future、またはその他のコンテナ内で結果をラップするという概念をキャプチャするために、いくつかのベース トレイトを定義し、実際にラップを行うメソッドを一緒に定義します。

import concurrent._

trait AbstractService {
  type Result[T]
  protected def result[T]( code: => T ) : Result[T]
}

Future次に、この基本特性をandOptionケースに特化します。

trait SyncService extends AbstractService {
  type Result[T] = Option[T]
  // Returns the original result wrapped in Some, 
  // or None if it was null or an exception occured
  protected def result[T]( code: => T ) : Option[T] = {
    try {
      Option( code )
    } catch{ case ex: Throwable =>
      ex.printStackTrace()
      None
    }
  }  
}

trait AsyncService extends AbstractService {
  type Result[T] = Future[T]
  protected val execContext: ExecutionContext
  protected def result[T]( code: => T ) : Future[T] = {
    future( code )( execContext )
  }
}

これで、次のように EntityGetService トレイトを定義できます。

trait EntityGetService[ID, ENTITY] extends AbstractService {
  def get( id: ID ): Result[ENTITY] = result {
    ???
  }

  // add all the other method implementations here, taking care to 
  // wrap the method bodies inside "result"
}

// Now specializing EntityGetService as a sync or async service is just a matter 
// of mixing SyncService or AsyncService:

class EntitySyncGetService[Long, Entity] extends EntityGetService[Long, Entity] with SyncService
class EntityAsyncGetService[Long, Entity]( implicit val execContext: ExecutionContext ) extends EntityGetService[Long, Entity] with AsyncService
于 2013-04-01T11:03:54.540 に答える