Skip to content

Instantly share code, notes, and snippets.

@lbialy
Last active October 15, 2018 09:29
Show Gist options
  • Save lbialy/912fad3c909374b81ce7 to your computer and use it in GitHub Desktop.
Save lbialy/912fad3c909374b81ce7 to your computer and use it in GitHub Desktop.
Scala - multiple approaches to Specification Pattern
object Specification {
type Spec[-A] = A => Boolean
implicit class SpecOps[A](_this: Spec[A]) {
def and(that: Spec[A]) = (item: A) => _this(item) && that(item)
def or(that: Spec[A]) = (item: A) => _this(item) || that(item)
def not = (item: A) => !_this(item)
}
}
import Specification._
case class Person(name: String, surname: String, gender: String)
val me = Person("Łukasz", "Biały", "M")
val hasMyName = (person: Person) => person.name == "Łukasz"
val hasMySurname = (person: Person) => person.surname == "Biały"
val isAGirl = (person: Person) => person.gender == "F"
val isMe = hasMyName and hasMySurname and isAGirl not
isMe(me)
object Specification {
type Spec[-A] = A => Boolean
def and[A](_this: Spec[A], that: Spec[A]) = (item: A) => _this(item) && that(item)
def or[A](_this: Spec[A], that: Spec[A]) = (item: A) => _this(item) || that(item)
def not[A](_this: Spec[A]) = (item: A) => !_this(item)
}
import Specification._
case class Person(name: String, surname: String, gender: String)
val me = Person("Łukasz", "Biały", "M")
val hasMyName = (person: Person) => person.name == "Łukasz"
val hasMySurname = (person: Person) => person.surname == "Biały"
val isAGirl = (person: Person) => person.gender == "F"
val isMe = and(and(hasMyName, hasMySurname), not(isAGirl))
isMe(me)
trait Specification[A] {
def isSatisfiedBy(item: A): Boolean
def and(that: Specification[A]) = new And(this, that)
def or(that: Specification[A]) = new Or(this, that)
def not() = new Not(this)
}
class And[A](val left: Specification[A], val right: Specification[A]) extends Specification[A] {
override def isSatisfiedBy(item: A) = (left isSatisfiedBy item) && (right isSatisfiedBy item)
}
class Or[A](val left: Specification[A], val right: Specification[A]) extends Specification[A] {
override def isSatisfiedBy(item: A) = (left isSatisfiedBy item) || (right isSatisfiedBy item)
}
class Not[A](val spec: Specification[A]) extends Specification[A] {
override def isSatisfiedBy(item: A) = !(spec isSatisfiedBy item)
}
case class Person(name: String, surname: String, gender: String)
class HasMyName extends Specification[Person] {
def isSatisfiedBy(person: Person) = person.name == "Łukasz"
}
class HasMySurname extends Specification[Person] {
def isSatisfiedBy(person: Person) = person.surname == "Biały"
}
class IsAGirl extends Specification[Person] {
def isSatisfiedBy(person: Person) = person.gender == "F"
}
val me = Person("Łukasz", "Biały", "M")
val isMe = (new HasMyName) and (new HasMySurname) and ((new IsAGirl) not)
isMe.isSatisfiedBy(me)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment