2014-01-23 2 views
3

Я работаю с установленным кодом базы в Акку и я вижу, эта картина очень много:Любой способ избежать определения метода реквизита в объекте компаньона Akka?

class Bar(a: A, b: B, c: C) extends Actor { 
    // body of actor 
} 

object Bar { 
    def props(a: A, b: B, c: C) = Props(new Bar(a = a, b = b, c = c) 
} 

Но метод реквизита чувствует себя некрасиво, как геттер/сеттер в Java. Есть лучший способ сделать это?

Я думал, что можно создать актера непосредственно, например.

var child = context.actorOf(Props(new Bar(a, b, c)) 

Поскольку это не намного сложнее, чем версия с использованием реквизита:

var child = context.actorOf(Bar.Props(a, b, c)) 

Однако если я понимаю, этот пост на Deprecation of Closures Taking Props то это плохая практика. Вместо этого они выступают за использование:

var child = context.actorOf(Props(classOf[Bar], a, b, c)) 

Но тогда это страдает от проблем с рефакторингом, так как контуры Райана ниже?

+3

Помещение 'Props' в объект-компаньон держит его ближе к определению созданного им актера и облегчает реорганизацию этого актера позже, так как у вас не будет нескольких« подставных », лежащих вокруг одного и того же актера. – Ryan

+0

Привет, Райан! Я наблюдаю точно противоположное. Эта конструкция делает рефакторинг хуже, потому что теперь мне нужно изменить все конструкторы и методы реквизита. Если нет других ограничений здесь, я не понимаю? Можете ли вы объяснить немного больше? –

+0

Вы неправильно поняли. Ваш первый пример - это то, что я защищал, а не тот, который вы добавили в свой пост. – Ryan

ответ

3

Помимо поддержания Props создания ближе к классу актера, он также помогает избежать случайного закрытия над this ссылкой актера, как это произойдет, если вы использовали Props(new MyActor("foo")) внутри другой актер.

Смотрите most recent reference guide section on Props:

Это также позволяет избежать ошибок, связанных с использованием метода Props.apply (...), который принимает по имени аргумента, так как в компаньона объект данного кода блок не сохранит ссылку на его охватывающий объем.

Если вы действительно не хотите использовать объект компаньона .props и хотят создать Props внутри другого актера, то вы должны использовать эту версию Props создателя для безопасности:

def apply(clazz: Class[_], args: Any*) 

Например :

context.actorOf(Props(classOf[MyActor], "foo")) 

Очевидным недостатком является то, что он не обеспечивает проверку типов параметров.

3

Основная причина, чтобы держать его ближе к классу, заключается в том, что речь идет об отражении, и вы не хотите, чтобы отражающие вызовы лежали вокруг всей вашей базы кода, потому что одно изменение в конструкторе вашего актера может сломать вещи во время выполнения и вы хотите, чтобы трассировка стека была как можно ближе к вашей проблеме (BTW, вы, похоже, не используете рефлексивный способ построения Actor в вашем примере).

EDIT

object MyActor { 
    def props(param: Int): Props = Props(classOf[MyActor], param) 
} 

class MyActor(param: Int) extends Actor { 
    def receive = ... 
} 

Если вы изменили конструктор MyActor принять, например, дополнительный параметр, например, так:

class MyActor(param: Int, param2: String) extends Actor { ... } 

ваш код компилируется нормально, но во время выполнения отражения API не сможет найти открытый конструктор, который соответствует вызову из Props(classOf[MyActor], param) так что будет сгенерировано исключение и вам будет видеть трассировку стека в журнале. Вы хотите, чтобы трассировка стека была как можно ближе к корню проблемы, поэтому вы можете быстрее найти/исправить проблему. Если бы все должны были использовать фабричный метод props, единственным местом, где все ваши трассировки стека (если они есть) приведут вас к определению, ну, фабричный метод props.

+0

Привет, agilesteel. Извините, я не понимаю, пожалуйста, можете ли вы привести примерный код? Я предполагаю, что вы обычно используете отражение, когда не знаете, что такое тип актера до времени исполнения. Здесь дело не в этом. –

+0

Я обновил ответ. – agilesteel

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