Вы спрашивали об этом примерно год назад, но есть еще одна возможность.Если вам когда-либо нужно вызвать только один метод:
def fooWithContext(cx: MyContextType)(params){
def bar(params) = ... qux() ...
def qux(params) = ... ged() ...
def ged(params) = ... mog() ...
def mog(params) = cx.doStuff(params)
... bar() ...
}
fooWithContext(makeContext())(params)
Если вам нужно, чтобы все методы были видимы извне:
case class Contextual(cx: MyContextType){
def foo(params) = ... bar() ...
def bar(params) = ... qux() ...
def qux(params) = ... ged() ...
def ged(params) = ... mog() ...
def mog(params) = cx.doStuff(params)
}
Contextual(makeContext()).foo(params)
Это в основном шаблон торта, за исключением того, что если всеваши вещи помещаются в один файл, вам не нужны все беспорядочные trait
вещи, чтобы объединить их в один объект: вы можете просто вложить их.Такое поведение также делает cx
правильно лексически ограниченным, поэтому вы не получите смешного поведения, когда будете использовать фьючерсы, актеров и тому подобное.Я подозреваю, что если вы используете новый AnyVal, вы можете даже избавиться от накладных расходов по выделению объекта Contextual
.
Если вы хотите разделить ваши вещи на несколько файлов, используя trait
s, вы толькона самом деле нужен один trait
на файл, чтобы хранить все и правильно поместить MyContextType
в область видимости, если вам не нужна необычная вещь заменяемых компонентов через наследование, которую есть в большинстве примеров шаблонов тортов.
// file1.scala
case class Contextual(cx: MyContextType) with Trait1 with Trait2{
def foo(params) = ... bar() ...
def bar(params) = ... qux() ...
}
// file2.scala
trait Trait1{ self: Contextual =>
def qux(params) = ... ged() ...
def ged(params) = ... mog() ...
}
// file3.scala
trait Trait2{ self: Contextual =>
def mog(params) = cx.doStuff(params)
}
// file4.scala
Contextual(makeContext()).foo(params)
В небольшом примере это выглядит несколько беспорядочно, но помните, что вам нужно разбить его на новую черту, только если код становится слишком большим, чтобы сидеть удобно в одном файле.К этому моменту ваши файлы становятся достаточно большими, поэтому дополнительные 2 строки стандартного файла на 200-500 строк не так уж и плохи.
РЕДАКТИРОВАТЬ:
Этотоже работает с асинхронными вещами
case class Contextual(cx: MyContextType){
def foo(params) = ... bar() ...
def bar(params) = ... qux() ...
def qux(params) = ... ged() ...
def ged(params) = ... mog() ...
def mog(params) = Future{ cx.doStuff(params) }
def mog2(params) = (0 to 100).par.map(x => x * cx.getSomeValue )
def mog3(params) = Props(new MyActor(cx.getSomeValue))
}
Contextual(makeContext()).foo(params)
Это Просто работает с использованием вложенности.Я был бы впечатлен, если бы вы могли получить подобную функциональность, работая с DynamicVariable
.
Вам понадобится специальный подкласс Future
, который хранит текущий DynamicVariable.value
при создании и подключается к ExecutionContext
'prepare()
или execute()
методу для извлечения value
и правильно установите DynamicVariable
перед выполнением Future
.
Тогда вам понадобится специальный scala.collection.parallel.TaskSupport
, чтобы сделать что-то подобное, чтобы заставить параллельные коллекции работать.И специальный akka.actor.Props
для того, чтобы сделать что-то подобное для , что .
Каждый раз, когда появляется новый механизм создания асинхронных задач, реализации на основе DynamicVariable
будут ломаться, и у вас будут странные ошибки, в результате которых вы получите неправильный Context
.Каждый раз, когда вы добавляете новый DynamicVariable
, чтобы отслеживать, вам нужно будет исправить всех ваших специальных исполнителей, чтобы правильно установить / сбросить этот новый DynamicVariable
.Используя вложение, вы можете просто позволить лексическому замыканию позаботиться обо всем этом для вас.
(я думаю Future
s, collections.parallel
и Prop
s считаются как "промежуточные слои, которые не являются моимикод ")