Тестирование с помощью замыканий
Перед тем, как подводить итоги, давайте рассмотрим еще одно применение замыканий Groovy. Рассмотрим приложение, которое моделирует компанию (Company
) с множеством работников (Employee
). Рекурсивное отношение организует агрегацию "один ко многим" между одним Employee
(руководитель группы) и многими Employee
(члены группы).
Вы можете использовать замыкания для оценки архитектурной целостности ваших моделей. Например, в рассматриваемом примере вы можете удостовериться, что каждому работнику назначен менеджер. Простое замыкание hasManager
выражает это требование для отдельно взятого сотрудника: def hasManager = { employee -> return (employee.manager != null) }
.
Частичное приложение замыкания forAll
из приведенного выше, в листинге 6, класса Functor
позволяет описать это условие как архитектурное требование: def everyEmployeeHasManager = Functor.forAll.curry(hasManager)
.
В листинге 11 показано приложение с замыканиями и каррингом для проверки архитектурной целостности системы.
Листинг 11. Применение замыканий для проверки архитектурной целостности
import fp.*
/**
* Компания с несколькими сотрудниками.
* Каждый работник отвечает перед руководителем группы,
* который, в свою очередь, управляет командой сотрудников.
*/
import java.util.*
class Employee {
@Property id
@Property name
@Property staff = [ : ]
@Property manager = null
String toString() {
return "Employee: ${id} ${name}"
}
def addToTeam(employee) {
staff[employee.id] = employee
employee.manager = this
}
}
class Company {
@Property name
@Property employees = [ : ]
def hireEmployee(employee) {
employees[employee.id] = employee
}
def displayStaff() {
println "Company: ${name}"
println "===================="
employees.each { entry -> println "
${entry.value}" }
}
}
def co = new Company(name : 'Napier')
def emp1 = new Employee(id : 123, name : 'KenB')
def emp2 = new Employee(id : 456, name : 'JohnS')
def emp3 = new Employee(id : 789, name : 'JonK')
co.hireEmployee(emp1)
co.hireEmployee(emp2)
co.hireEmployee(emp3)
emp3.addToTeam(emp1)
emp3.addToTeam(emp2)
co.displayStaff()
// Архитектурные замыкания
def hasManager = { employee -> return (employee.manager != null) }
def everyEmployeeHasManager = Functor.forAll.curry(hasManager)
def staff = new ArrayList(co.employees.values())
println "Every employee has a manager?:
${everyEmployeeHasManager.call(staff)}" // false