2010-08-01 2 views
6

В настоящее время я открываю scala, и мне было интересно, могу ли я использовать черты с фабрикой.Использование черт с фабрикой

Я попытался это:

 
abstract class Foo { 
    ... 
} 
object Foo { 
    def apply() = new Bar 

    private class Bar extends Foo { 
    ... 
    } 
} 

Foo() with MyTrait // Not working 

Я думаю, это потому, что with должно предшествовать new.

Итак, есть ли способ сделать это?

Спасибо

+0

Возможный дубликат [Как создать экземпляр признака в общем методе в scala?] (Http://stackoverflow.com/questions/3274279/how-do-i-create-an-instance -of-a-trait-in-a-generic-method-in-scala) –

ответ

4

Нет, это слишком поздно, экземпляр уже создан, когда применяется() возвращает метод.

Что вы можете сделать, это использовать черты внутри фабричного метода. Код ниже с довольно большим примером кода я пишу:

object Avatar { 
// Avatar factory method 
def apply(name: String, race: RaceType.Value, character: CharacterType.Value 
): Avatar = { 
    race match { 
     case RaceType.Dwarf => { 
     character match { 
      case CharacterType.Thief => new Avatar(name) with Dwarf with Thief 
      case CharacterType.Warrior => new Avatar(name) with Dwarf with Warrior 
      case CharacterType.Wizard => new Avatar(name) with Dwarf with Wizard 
     } 
     } 
     case RaceType.Elf => { 
     character match { 
      case CharacterType.Thief => new Avatar(name) with Elf with Thief 
      case CharacterType.Warrior => new Avatar(name) with Elf with Warrior 
      case CharacterType.Wizard => new Avatar(name) with Elf with Wizard 
     } 
     } 
    } 
    } 
} 

class Avatar(val name: String) extends Character { 
    ... 
} 

В этом коде типа (профессия и раса) ваш аватар решается на заводе на основе RaceType и CharacterType перечислениях. У вас есть один завод для всех видов разных типов или комбинаций типов.

+1

В вашем случае мы должны заранее знать отличительные черты, которые мы могли бы использовать. Но если мы этого не сделаем, возможно ли передать черты в фабричный метод с определением в идее 'def apply [T]() = new Foo с T'? –

+2

@Mr_Qqn: Нет, вы не можете этого сделать, даже не проходя манифест. Если вам нужно это поведение, планируйте создание прокси-серверов, которые проксируют определенные черты для объекта, который создает ваш завод, и создают (неявные) преобразования для тех свойств, которые создают необходимые прокси. –

+1

Спасибо, он отлично работает с прокси. Но что вы подразумеваете, создавая неявные преобразования? «Новый FooProxy с MyTrait» выполняет работу правильно. –

3

Скажем, у вас есть:

class Foo 
object Foo { def apply() = new Foo } 
trait Baz 

Тогда:

Foo() with Baz 

будет аналогична:

val foo = new Foo 
foo with Baz 

, который будет означать своего рода наследования на базе прототипа, который Безразлично Scala Не знаю. (Насколько я знаю.)

(Я бы предположил, что ошибка в мышлении интуитивно ошибочно принимает знак = для «знака замены». То есть, поскольку Foo() означает Foo.apply() и который «равно», новый Foo, вы можете substitue Foo() с новым Foo. что, очевидно, вы не можете.)

3

решения с неявным преобразованием

Кен предположил, что прокси-сервер может помочь нам в этом случае. То, что мы пытаемся сделать здесь, - добавить черту к экземпляру после его создания. Это «исправление обезьян» может быть полезно, если кто-то написал класс (и метод apply()), и вы не можете получить доступ к источнику. В этом случае вы можете сделать, это добавить прокси/обертку поверх экземпляра с помощью неявного преобразования (без ручного преобразования требуется):


Используя Foo пример мы могли бы сделать это так:

class Foo 
object Foo { def apply() = new Foo } 
trait Baz { def usefulMethod(s: String) = "I am really useful, "+ s } 

// ---- Proxy/Wrapper ---- 
class FooWithBazProxy extends Foo with Baz 

// --- Implicit conversion --- 
implicit def foo2FooWithBazProxy(foo: Foo): FooWithBazProxy = new FooWithBazProxy 

// --- Dummy testcode --- 
val foo = Foo() 
println(foo.usefulMethod("not!")) 

Выходы:

I am really useful, not! 

причина мне не нравится этот пример является:

Baz не использует Foo в любом случае.Трудно понять, почему мы хотели бы присоединить usefulMethod() к Foo.


Так что я сделал новый пример, где черта мы «обезьяна патч» в экземпляр фактически использует экземпляр:

// --------- Predefined types ----------- 
trait Race { 
    def getName: String 
} 

class Avatar(val name: String) extends Race{ 
    override def getName = name 
} 

object Avatar{ 
    def apply() = new Avatar("Xerxes") 
} 

// ---------- Your new trait ----------- 
trait Elf extends Race { 
    def whoAmI = "I am "+ getName + ", the Elf. " 
} 

// ---- Proxy/Wrapper ---- 
class AvatarElfProxy(override val name: String) extends Avatar(name) with Elf 

// ---- Implicit conversion ---- 
implicit def avatar2AvatarElfProxy(Avatar: Avatar): AvatarElfProxy = new AvatarElfProxy(Avatar.name) 


// --- Dummy testcode --- 
val xerxes= Avatar() 
println(xerxes.whoAmI) 

Печать:

I am Xerxes, the Elf. 

В этом примере добавленный признак Elf использует метод getName экземпляра, который он расширяет.

Был бы благодарен, если вы увидели какие-либо ошибки, я не очень хорошо разбираюсь (пока).

+0

Я продлил ваше решение, чтобы включить такой код, как 'val xerxes = Avatar [Elf] (" Xerxes ")' –

2

решение с прокси и неявного преобразования

Этот пример расширяет решение OLLE, чтобы позволить пользователю указать Mixin признака при вызове метода apply() (например val xerxes = Avatar[Elf]("Xerxes")).

// ----- Predefined types ----- 

trait Race { 
    def whoAmI: String 
} 

class Avatar[R <: Race](val name: String) 

object Avatar { 
    def apply[R <: Race](name: String) = new Avatar[R](name) 
} 

// ----- Generic proxy ----- 
class AvatarProxy[R <: Race](val avatar: Avatar[R]) 

implicit def proxy2Avatar[R <: Race](proxy: AvatarProxy[R]): Avatar[R] = 
     proxy.avatar 

// ----- A new trait ----- 
trait Elf extends Race { 
    self: AvatarProxy[Elf] => 
    def whoAmI = "I am " + self.name + ", the Elf." 
} 

implicit def avatar2Elf(avatar: Avatar[Elf]): AvatarProxy[Elf] with Elf = 
     new AvatarProxy[Elf](avatar) with Elf 

// --- Test code ----- 
val xerxes = Avatar[Elf]("Xerxes") 
println(xerxes.whoAmI) 

Печать:

Я Ксеркс, Эльф.

Смежные вопросы