Мы пришли к мысли, что необходим какой-то предметный язык для описания всех этих типов объектов и отношений. Здесь 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.0com.exampledsl0.0.1-SNAPSHOTjar 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.samplesclass 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.dslimport static org.junit.Assert.assertEqualsimport static org.junit.Assert.assertNotNullimport org.junit.Testimport com.example.dsl.samples.SampleOrganizationclass 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