Мы пришли к мысли, что необходим какой-то предметный язык для описания всех этих типов объектов и отношений. Здесь Groovy пришел на помощь. В этом посте я хотел бы продемонстрировать, насколько мощным и выразительным может быть простой DSL, написанный с использованием сборщиков Groovy .
Как всегда, давайте начнем с файла POM для нашего примера проекта:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
4.0.0 com.example dsl 0.0.1-SNAPSHOT jar UTF-8 junit junit 4.10 org.codehaus.groovy groovy-all 1.8.4 org.codehaus.gmaven gmaven-plugin 1.4 1.8 compile testCompile org.apache.maven.plugins maven-compiler-plugin 2.3.1 1.6 1.6 |
Я буду использовать последнюю версию Groovy , 1.8.4. Наша модель домена будет включать три класса: Организация , Пользователь и Группа . У каждой организации есть обязательное имя, несколько пользователей и несколько групп. Каждая группа может иметь несколько пользователей в качестве участников. Довольно просто, поэтому вот наши классы Java.
Organization.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
package com.example; import java.util.Collection; public class Organization { private String name; private Collection< User > users = new ArrayList< User >(); private Collection< Group > groups = new ArrayList< Group >(); public String getName() { return name; } public void setName( final String name ) { this .name = name; } public Collection< Group > getGroups() { return groups; } public void setGroups( final Collection< Group > groups ) { this .groups = groups; } public Collection< User > getUsers() { return users; } public void setUsers( final Collection< User > users ) { this .users = users; } } |
User.java
01
02
03
04
05
06
07
08
09
10
11
12
13
|
package com.example; public class User { private String name; public String getName() { return name; } public void setName( final String name ) { this .name = name; } } |
Группа .java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
package com.example; import java.util.Collection; public class Group { private String name; private Collection< User > users = new ArrayList< User >(); public void setName( final String name ) { this .name = name; } public String getName() { return name; } public Collection< User > getUsers() { return users; } public void setUsers( final Collection< User > users ) { this .users = users; } } |
Теперь у нас есть модель предметной области. Давайте подумаем, как обычный пользователь может описать свою организацию с пользователями, группами и отношениями между всеми этими объектами. Прежде всего, мы выбираем какой-то понятный человеку язык, достаточно простой для понимания обычным пользователем. Познакомьтесь с Groovy строителями.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
package com.example.dsl.samples class SampleOrganization { def build() { def builder = new ObjectGraphBuilder( classLoader: SampleOrganization. class .classLoader, classNameResolver: "com.example" ) return builder.organization( name: "Sample Organization" ) { users = [ user( id: "john" , name: "John" ), user( id: "samanta" , name: "Samanta" ), user( id: "tom" , name: "Tom" ) ] groups = [ group( id: "administrators" , name: "administrators" , users: [ john, tom ] ), group( id: "managers" , name: "managers" , users: [ samanta ] ) ] } } } |
И вот небольшой тестовый пример, который подтверждает, что наша модель предметной области соответствует ожиданиям:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
package com.example.dsl import static org.junit.Assert.assertEquals import static org.junit.Assert.assertNotNull import org.junit.Test import com.example.dsl.samples.SampleOrganization class BuilderTestCase { @Test void 'build organization and verify users, groups' () { def organization = new SampleOrganization().build() assertEquals 3 , organization.users.size() assertEquals 2 , organization.groups.size() assertEquals "Sample Organization" , organization.name } } |
Я использую этот простой DSL снова и снова во многих проектах. Это действительно упрощает создание множества сложных объектных моделей.
Справка: простой, но мощный DSL с использованием Groovy от нашего партнера по JCG