Существует ли в природе описание паттернов, техник проектирования в контексте Scala ? На сайте Scala рассмотрены только неск. простейших паттернов.
Аноним,
А>Существует ли в природе описание паттернов, техник проектирования в контексте Scala ? На сайте Scala рассмотрены только неск. простейших паттернов.
Мартин утверждает, что в Скале лучше всего делать высокоуровневые объекты в соответствии с декомпозицией на объекты и обобщая классы до трейтов (и возможно, параметризуя их и выделяя зависимые типы). Набор методов в трейтах необязательно должен быть минимальным. Подход на самом деле немного отличается от "интерфейсного" подхода (оригинальная статья [url=
http://www.iam.unibe.ch/~scg/Archive/Papers/Scha03aTraits.pdf]Traits: Composable Units of Behaviour[url]). Реализацию по-возможности делать в функциональном стиле, то есть использовать алгебраические типы данных, а методы в классах будут оперировать над этими АТД. Передачи интерфейсов и всяких коллбэков по-возможности заменять на ФВП.
Я приведу пример, который можно найти в стандартной библиотеке, маленький, но тем не менее общий. Трейт InputChannel описывает нечто, что умеет принимать сообщения, трейт OutputChannel описывает нечто, что умеет отправлять сообщения. Они определены как
trait InputChannel[+Msg] {
// получить сообщение
def receive[R](f: PartialFunction[Msg, R]): R
}
trait OutputChannel[-Msg] {
// отправить сообщение
def !(msg: Msg): Unit
}
(в этих трейтах конечно ещё есть методы, но это неважно). Теперь сущность, которая умеет принимать и отправлять сообщения можно описать как
// используется в методе Channel.!
// ещё один ! определён в классе Actor
case class ! [a](ch: Channel[a], msg: a)
class Channel[Msg] extends InputChannel[Msg] with OutputChannel[Msg] {
private var recv: Actor = {...}
// конструктор
def this(recv: Actor) = {
this()
this.recv = recv
}
...
def !(msg: Msg) {
recv ! scala.actors.!(this, msg)
}
...
def receive[R](f: PartialFunction[Msg, R]): R = {
val C = this.asInstanceOf[Channel[Any]]
recv.receive {
case C ! msg if (f.isDefinedAt(msg.asInstanceOf[Msg])) => f(msg.asInstanceOf[Msg])
}
}
...
}
Теперь этот класс можно инстанцировать и использовать
val channel = new Channel[Any](anActor)
channel ! "message"
channel receive {
msg => Console.println(msg)
}
Как видишь, здесь присутствует как-бы множественное наследование. На самом деле конечно просто mixin composition, с последним, в отличие от МН проблем бы не возникло даже, если бы receive и ! имели реализации в трейтах InputChannel & OutputChannel соответственно.