trait Factory[Output] extends Serializable
A factory to create new instances, especially dynamic mix-ins.
Author:
杨博 (Yang Bo) <[email protected]>
- 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
@inject
method 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 compile
If the trait does not contain abstract methods other than
@inject
methods, 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 inner
whose 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 type
compile 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 inOutput
according 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)