trait Factory[Output] extends Serializable
A factory to create new instances, especially dynamic mix-ins.
Author:
杨博 (Yang Bo) <pop.atry@gmail.com>
- Source
- Factory.scala
Given a trait that has abstract members.
trait Foo { val myValue: String var myVariable: Long def myMethod0(): Option[Double] def myMethod2(p0: Int, p1: Int): Int def myCurriedMethod(seq: Seq[Int])(mapper: Int => String): Seq[String] // Methods without pararmeters is disabled for now, due to https://github.com/scala/bug/issues/10647 // def myByNameMethod: Option[Int] }
When creating a factory for the trait.
val factory = Factory[Foo]Then the newInstance method of the factory should accept named arguments according to abstract members.
val createdFromNamedArguments: Foo = factory.newInstance( myValue = "string value", myVariable = 42L, myMethod0 = () => Some(0.5), myMethod2 = _ + _, myCurriedMethod = seq => mapper => seq.map(mapper) ) createdFromNamedArguments.myValue should be("string value") createdFromNamedArguments.myVariable should be(42L) createdFromNamedArguments.myMethod0() should be(Some(0.5)) createdFromNamedArguments.myMethod0() shouldNot be theSameInstanceAs createdFromNamedArguments.myMethod0() createdFromNamedArguments.myMethod2(1000, 24) should be(1024) createdFromNamedArguments.myCurriedMethod(Seq(2, 3, 4))(_.toString) should be(Seq("2", "3", "4"))
When using unnamed parameters, the parameters should be passed in alphabetical order
val createdFromUnnamedArguments: Foo = factory.newInstance( seq => mapper => seq.map(mapper), // myCurriedMethod () => Some(0.5), // myMethod0 _ + _, // myMethod2 "string value", // myValue 42L // myVariable )
, Given two traits that have no abstract member.
trait Foo trait Bar
When creating a factory for mix-in type of the two types.
val factory = Factory[Foo with Bar]
Then the newInstance method of the factory should accept no parameters.
val fooBar: Foo with Bar = factory.newInstance() fooBar should be(a[Foo]) fooBar should be(a[Bar])
, Given a trait that contains an abstract method annotated as @inject.
import com.thoughtworks.feature.Factory.inject trait Foo[A] { @inject def orderingA: Ordering[A] }
When creating a factory for the trait
val factory = Factory[Foo[Int]]
Then the
@injectmethod will be replaced to an implicit value.val foo = factory.newInstance() foo.orderingA should be(implicitly[Ordering[Int]])
It will not compile if no implicit value found. For example,
Foo[Symbol]requires an implicit value of typeOrdering[Symbol], which is not availble."Factory[Foo[Symbol]]" shouldNot compileIf the trait does not contain abstract methods other than
@injectmethods, then the factory type class is a Factory.Factory0, which can be summoned by Predef.implicitly,val nullaryFactory = implicitly[Factory.Factory0[Foo[Int]]]
and newInstance method is available on the Factory.Factory0 as well.
nullaryFactory.newInstance().orderingA should be(implicitly[Ordering[Int]])- Note
However, if the nested type is an alias to another type outside of the type to create, then it is allowed
trait Outer { type Inner = String val inner: Option[Inner] } val outer: Outer = Factory[Outer].newInstance(inner = Some("my value")) outer.inner should be(Some("my value"))
,This Factory disallows creating types that has an abstract member whose type depends on nested types. Given an abstract
val innerwhose type is theInner,trait Outer { trait Inner val inner: Option[Inner] }
then the attempt to create factory for
,Outer, likeFactory[Outer].newInstance(inner = None), will cause avalue inner has incompatible typecompile error.@inject works on implicit abstract methods as well.
import com.thoughtworks.feature.Factory.inject trait Foo[A] { @inject implicit def orderingA: Ordering[A] } Factory[Foo[Int]].newInstance().orderingA should be(implicitly[Ordering[Int]])
,Factories may be nested
import com.thoughtworks.feature.Factory.inject import com.thoughtworks.feature.Factory.Factory1 import com.thoughtworks.feature.ByName.`=>` trait Outer { trait AbstractParameterApi type AbstractParameter <: AbstractParameterApi trait InnerApi { def foo: AbstractParameter } type Inner <: InnerApi @inject val innerFactory: Factory1[`=>`[AbstractParameter], Inner] } val outer = Factory[Outer].newInstance() outer.innerFactory.newInstance(new outer.AbstractParameterApi {}) should be(an[outer.Inner])
,Factories may create types that contains refinement types
trait SomeBuilder { type A def makeSome(a: A) = Some(a) } val someBuilder = Factory[SomeBuilder { type A = Int }].newInstance() someBuilder.makeSome(42) should be(Some(42))
- Alphabetic
- By Inheritance
- Factory
- Serializable
- Serializable
- AnyRef
- Any
- by any2stringadd
- by StringFormat
- by Ensuring
- by ArrowAssoc
- Hide All
- Show All
- Public
- All
Type Members
-
abstract
type
Constructor
A function type that returns
Output.A function type that returns
Output.The parameter types are all abstract members in
Output
Abstract Value Members
-
abstract
val
newInstance: Constructor
Returns an instance of
Output, which overrides abstract members inOutputaccording to parameters pass to this newInstance method.
Concrete Value Members
-
final
def
!=(arg0: Any): Boolean
- Definition Classes
- AnyRef → Any
-
final
def
##(): Int
- Definition Classes
- AnyRef → Any
- def +(other: String): String
- def ->[B](y: B): (Factory[Output], B)
-
final
def
==(arg0: Any): Boolean
- Definition Classes
- AnyRef → Any
-
final
def
asInstanceOf[T0]: T0
- Definition Classes
- Any
-
def
clone(): AnyRef
- Attributes
- protected[java.lang]
- Definition Classes
- AnyRef
- Annotations
- @native() @throws( ... )
- def ensuring(cond: (Factory[Output]) ⇒ Boolean, msg: ⇒ Any): Factory[Output]
- def ensuring(cond: (Factory[Output]) ⇒ Boolean): Factory[Output]
- def ensuring(cond: Boolean, msg: ⇒ Any): Factory[Output]
- def ensuring(cond: Boolean): Factory[Output]
-
final
def
eq(arg0: AnyRef): Boolean
- Definition Classes
- AnyRef
-
def
equals(arg0: Any): Boolean
- Definition Classes
- AnyRef → Any
-
def
finalize(): Unit
- Attributes
- protected[java.lang]
- Definition Classes
- AnyRef
- Annotations
- @throws( classOf[java.lang.Throwable] )
- def formatted(fmtstr: String): String
-
final
def
getClass(): Class[_]
- Definition Classes
- AnyRef → Any
- Annotations
- @native()
-
def
hashCode(): Int
- Definition Classes
- AnyRef → Any
- Annotations
- @native()
-
final
def
isInstanceOf[T0]: Boolean
- Definition Classes
- Any
-
final
def
ne(arg0: AnyRef): Boolean
- Definition Classes
- AnyRef
-
final
def
notify(): Unit
- Definition Classes
- AnyRef
- Annotations
- @native()
-
final
def
notifyAll(): Unit
- Definition Classes
- AnyRef
- Annotations
- @native()
-
final
def
synchronized[T0](arg0: ⇒ T0): T0
- Definition Classes
- AnyRef
-
def
toString(): String
- Definition Classes
- AnyRef → Any
-
final
def
wait(): Unit
- Definition Classes
- AnyRef
- Annotations
- @throws( ... )
-
final
def
wait(arg0: Long, arg1: Int): Unit
- Definition Classes
- AnyRef
- Annotations
- @throws( ... )
-
final
def
wait(arg0: Long): Unit
- Definition Classes
- AnyRef
- Annotations
- @native() @throws( ... )
- def →[B](y: B): (Factory[Output], B)