SlideShare a Scribd company logo
1 of 69
Download to read offline
Bob	the	Builder_
Alexander	(Sascha)	Klein	<alexander.klein@codecentric.de>
 
1
Bob	the	Builder
 
2
About	me
Alexander	Klein
Branchmanager
codecentric	AG
Curiestr.	2
70563	Stuttgart,	Germany
	+49	(0)	172	529	40	20
	alexander.klein@codecentric.de
	www.codecentric.de
	blog.codecentric.de
	@saschaklein
 
3
Bobs	project
 
4
Domain
House
Material
@Canonical
class	House	{
				int	number
				Material	material
				Roof	roof
				List<Level>	level	=	[]
}
enum	Material	{
				Bricks,	Wood,	Concrete
}
 
5
Domain
Roof
@Canonical
class	Roof	{
				static	String	MATERIAL_TILES	=	'Tiles'
				static	String	MATERIAL_REED	=	'Reed'
				static	String	MATERIAL_SHINGLES	=	'Shingles'
				String	material
				String	color
}
 
6
Domain
Level
Room
@Canonical
class	Level	{
				String	floor
				List<Room>	rooms	=	[]
}
@Canonical
class	Room	{
				String	name
				List<Room>	rooms	=	[]
}
 
7
Builder	Pattern
 
8
Java	Builder	Pattern
 
9
Java	Builder	Pattern
		static	main(def	args)	{
						prettyPrint	House.builder()
										.number(1)
										.material(Material.Bricks)
										.roof(Roof.builder().material(Roof.MATERIAL_TILES).color('Red').build())
										.level([
										Level.builder().floor('1nd	floor').rooms([
																		Room.builder().name('Bedroom').build(),
																		Room.builder().name('Childrens	room').build()
										]).build(),
										Level.builder().floor('Ground	floor').rooms([
																		Room.builder().name('Living	room').build(),
																		Room.builder().name('Kitchen').build()
										]).build(),
										Level.builder().floor('Basement').rooms([
																		Room.builder().name('Laundry').build(),
																		Room.builder().name('Cellar').rooms([
																										Room.builder().name('Food	storage').build(),
																										Room.builder().name('Store	room').build()
																		]).build()
										]).build()
						]).build()
		}
 
10
Java	Builder	Pattern
{
		<House>
		material:	Bricks,	number:	1,	roof:	{	<Roof>	material:	Tiles,	color:	Red	}
		level			:	[	{
																<Level>	floor:	1nd	floor,	rooms:	[
																		{	<Room>	rooms:	null,	name:	Bedroom	},
																		{	<Room>	rooms:	null,	name:	Childrens	room	}
																]
														},
														{
																<Level>	floor:	Ground	floor,	rooms:	[
																		{	<Room>	rooms:	null,	name:	Living	room},
																		{	<Room>	rooms:	null	name:	Kitchen}
																]
														},
														{
																<Level>	floor:	Basement,	rooms:	[
																		{	<Room>	rooms:	null,	name:	Laundry	},
																		{	<Room>	name:	Cellar,		rooms:	[
																						{	<Room>	rooms:	null,	name:	Food	storage	},
																						{	<Room>	rooms:	null,	name:	Store	room	}
																				]
																		}
																]
														}
												]
}
 
11
@Builder
House
same	with	the	other	classes
@Builder
@Canonical
class	House	{
				int	number
				Material	material
				Roof	roof
				List<Level>	level	=	[]
}
 
12
Groovy	Builder	Pattern
 
13
Groovy	Builder	Pattern
				static	main(def	args)	{
								House	house	=	this.newInstance().house(number:	1)	{
												material('Bricks')
												roof('tiles',	color:	'Red')
												level('1nd	floor')	{
																room(name:	'Bedroom')
																room('Childrens	room')
												}
												level('Ground	floor')	{
																room('Living	room')
																room('Kitchen')
												}
												level('Basement')	{
																room('Laundry')
																room('Cellar')	{
																				room('Food	storage')
																				room('Store	room')
																}
												}
								}
								prettyPrint(house)
				}
 
14
Groovy	Builder	Pattern
{
		<House>
		material:	Bricks,	number:	1,	roof:	{	<Roof>	material:	Tiles,	color:	Red	}
		level			:	[	{
																<Level>	floor:	1nd	floor,	rooms:	[
																		{	<Room>	rooms:	null,	name:	Bedroom	},
																		{	<Room>	rooms:	null,	name:	Childrens	room	}
																]
														},
														{
																<Level>	floor:	Ground	floor,	rooms:	[
																		{	<Room>	rooms:	null,	name:	Living	room},
																		{	<Room>	rooms:	null	name:	Kitchen}
																]
														},
														{
																<Level>	floor:	Basement,	rooms:	[
																		{	<Room>	rooms:	null,	name:	Laundry	},
																		{	<Room>	name:	Cellar,		rooms:	[
																						{	<Room>	rooms:	null,	name:	Food	storage	},
																						{	<Room>	rooms:	null,	name:	Store	room	}
																				]
																		}
																]
														}
												]
}
 
15
Groovy	Builder	Pattern
General	contract
node	to	create	→	method-name
0..1	values
often	used	as	value	for	an	important	attribute
0..n	attributes
0..1	Closure	for	subnodes
node(value?,	attributes*)	{
				subnode(value?,	attributes*)	{
								leaf(value?,	attributes*)
				}
}
 
16
Handcraft
 
17
Handcraft
Scaffolding
Result
class	Handcraft1	{
				House	house(Closure	blueprint)	{
								House	house	=	new	House()
								Closure	plan	=	blueprint.clone()
								plan.delegate	=	this
								plan.resolveStrategy	=	Closure.DELEGATE_ONLY	//	OR	DELEGATE_FIRST
								plan()
								return	house
				}
				static	main(def	args)	{
								House	house	=	this.newInstance().house	{}
								prettyPrint(house)
				}
}
{
		<House>	material:	null,	roof:	null,	number:	0,	level:	[]
}
 
18
Handcraft
Adding	details
import	static	bob.v1.Material.Bricks
class	Handcraft2	{
				House	house(Map	attributes	=	[:],	Closure	blueprint	=	{})	{
								House	house	=	new	House(attributes)
								Closure	plan	=	blueprint.clone()
								plan.delegate	=	this
								plan.resolveStrategy	=	Closure.DELEGATE_ONLY
								plan()
								return	house
				}
				static	main(def	args)	{
								House	house	=	this.newInstance().house(number:	1,	material:	Bricks)
								prettyPrint(house)
				}
}
 
19
Handcraft
Result
{
		<House>	material:	Bricks,	roof:	null,	number:	1,	level:	[]
}
 
20
Handcraft
Roofing
…​
				House	house
				House	house(Map	attributes	=	[:],	Closure	blueprint	=	{})	{
								house	=	new	House(attributes)
				void	roof(Map	attributes	=	[:],	String	material)	{
								Roof	roof	=	new	Roof(attributes)
								roof.material	=	material
								house.roof	=	roof
				}
				static	main(def	args)	{
								House	house	=	this.newInstance().house(number:	1,	material:	Bricks)	{
												roof('tiles',	color:	'Red')
								}
								prettyPrint(house)
				}
 
21
Handcraft
Result
{
		<House>	material:	Bricks,
										number:	1,
										roof		:	{	<Roof>	material:	tiles,	color:	Red	},
										level	:	[]
}
 
22
Handcraft
Refactoring
				House	house
				House	house(Map	attributes	=	[:],	Closure	blueprint	=	{})	{
								house	=	new	House(attributes)
								runClosure(blueprint)
								return	house
				}
				private	runClosure(Closure	cls)	{
								if	(cls)	{
												Closure	clone	=	cls.clone()
												clone.delegate	=	this
												clone.resolveStrategy	=	Closure.DELEGATE_ONLY
												clone()
								}
				}
				//	...
 
23
Handcraft
Storing	the	context
				List	stack	=	[]
				def	parent
				def	current
				private	runClosure(Closure	cls,	def	instance)	{
								parent	=	stack	?	stack?.last()	:	null
								stack.push(instance)
								current	=	instance
								if	(cls)	{
												Closure	clone	=	cls.clone()
												clone.delegate	=	this
												clone.resolveStrategy	=	Closure.DELEGATE_ONLY
												clone()
								}
								current	=	stack	?	stack.last()	:	null
								stack.pop()
								parent	=	stack	?	stack.last()	:	null
				}
 
24
Handcraft
Creating	the	stories
				void	level(String	floor,	Closure	blueprint	=	{})	{
								Level	level	=	new	Level(floor:	floor)
								runClosure(blueprint,	level)
								parent.level	<<	level
				}
				static	main(def	args)	{
								House	house	=	this.newInstance().house(number:	1,	material:	Bricks)	{
												roof('tiles',	color:	'Red')
												level('1nd	floor')
												level('Ground	floor')
												level('Basement')
								}
								prettyPrint(house)
				}
 
25
Handcraft
Result
{
		<House>	material	:	Bricks,
										number	:	1
										roof			:	{	<Roof>	material:	tiles,	color:	Red	},
										level		:	[
																					{	<Level>	floor:	1nd	floor,	rooms:	[]	},
																					{	<Level>	floor:	Ground	floor,	rooms:	[]	},
																					{	<Level>	floor:	Basement,	rooms:	[]	}
																			]
}
 
26
Handcraft
Material	as	a	node
				void	material(def	material)	{
								if	(material	instanceof	String)
												material	=	Material.valueOf(material)
								current.material	=	material
				}
				static	main(def	args)	{
								House	house	=	this.newInstance().house(number:	1)	{
												material('Bricks')
												roof('tiles',	color:	'Red')
												level('1nd	floor')
												level('Ground	floor')
												level('Basement')
								}
								prettyPrint(house)
				}
 
27
Handcraft
Result
{
		<House>	material	:	Bricks,
										number	:	1
										roof			:	{	<Roof>	material:	tiles,	color:	Red	},
										level		:	[
																					{	<Level>	floor:	1nd	floor,	rooms:	[]	},
																					{	<Level>	floor:	Ground	floor,	rooms:	[]	},
																					{	<Level>	floor:	Basement,	rooms:	[]	}
																			]
}
 
28
Handcraft
Building	the	rooms
				static	main(def	args)	{
								House	house	=	this.newInstance().house(number:	1)	{
												material('Bricks')
												roof('tiles',	color:	'Red')
												level('1nd	floor')	{
																room(name:	'Bedroom')
																room('Childrens	room')
												}
												level('Ground	floor')	{
																room('Living	room')
																room('Kitchen')
												}
												level('Basement')	{
																room('Laundry')
																room('Cellar')	{
																				room('Food	storage')
																				room('Store	room')
																}
												}
								}
								prettyPrint(house)
				}
 
29
Handcraft
Building	the	rooms
				void	room(String	name,	Closure	blueprint	=	null)	{
								room([:],	name,	blueprint)
				}
				void	room(Map	attributes,	String	name	=	null,	Closure	blueprint	=	null)	{
								Room	room	=	new	Room(attributes)
								if	(name	!=	null)	room.name	=	name
								runClosure(blueprint,	room)
								parent.rooms	<<	room
				}
 
30
Handcraft
{
		<House>
		material:	Bricks,	number:	1,	roof:	{	<Roof>	material:	Tiles,	color:	Red	}
		level			:	[	{
																<Level>	floor:	1nd	floor,	rooms:	[
																		{	<Room>	rooms:	null,	name:	Bedroom	},
																		{	<Room>	rooms:	null,	name:	Childrens	room	}
																]
														},
														{
																<Level>	floor:	Ground	floor,	rooms:	[
																		{	<Room>	rooms:	null,	name:	Living	room},
																		{	<Room>	rooms:	null	name:	Kitchen}
																]
														},
														{
																<Level>	floor:	Basement,	rooms:	[
																		{	<Room>	rooms:	null,	name:	Laundry	},
																		{	<Room>	name:	Cellar,		rooms:	[
																						{	<Room>	rooms:	null,	name:	Food	storage	},
																						{	<Room>	rooms:	null,	name:	Store	room	}
																				]
																		}
																]
														}
												]
}
 
31
Using	a	plant
 
32
Using	a	plant
groovy.util.BuilderSupport
 
33
Using	a	plant
Scaffolding
class	Plant1	extends	BuilderSupport	{
				@Override	protected	Object	createNode(Object	name,	Map	attributes	=	[:])	{
								return	createNode(name,	attributes,	null)
				}
				@Override	protected	Object	createNode(Object	name,	Map	attributes	=	[:],	Object	value)	{
								switch	(name)	{
												case	'house':	return	new	House(attributes)
												default:	return	null
								}
				}
				@Override	protected	void	setParent(Object	parent,	Object	child)	{}
				static	main(def	args)	{
								House	house	=	this.newInstance().house(number:	1)	{}
								prettyPrint(house)
				}
}
 
34
Using	a	plant
Adding	details
				@Override	protected	Object	createNode(Object	name,	Map	attributes	=	[:],	Object	value){
								switch	(name)	{
												case	'house':	return	new	House(attributes)
												case	'roof':	return	new	Roof(attributes	+	[material:	value])
												default:	return	null
								}
				}
				@Override	protected	void	setParent(Object	parent,	Object	child)	{
								switch	(child)	{
												case	Roof:	parent.roof	=	child;	break
								}
				}
				static	main(def	args)	{
								House	house	=	this.newInstance().house(number:	1)	{
												roof('tiles',	color:	'Red')
								}
								prettyPrint(house)
				}
 
35
Using	a	plant
Roofs	and	storages
				@Override	protected	Object	createNode(Object	name,	Map	attributes	=	[:],	Object	value){
								switch	(name)	{
												case	'house':	return	new	House(attributes)
												case	'roof':	return	new	Roof(attributes	+	[material:	value])
												case	'level':	return	new	Level(floor:	value)
												default:	return	null
								}
				}
				@Override	protected	void	setParent(Object	parent,	Object	child)	{
								switch	(child)	{
												case	Roof:	parent.roof	=	child;	break
												case	Level:	parent.level	<<	child;	break
								}
				}
 
36
Using	a	plant
Roofs	and	storages
				static	main(def	args)	{
								House	house	=	this.newInstance().house(number:	1)	{
												roof('tiles',	color:	'Red')
												level('1nd	floor')	{}
												level('Ground	floor')	{}
												level('Basement')	{}
								}
								prettyPrint(house)
				}
 
37
Using	a	plant
Material	as	a	node
				@Override	protected	Object	createNode(Object	name,	Map	attributes	=	[:],	Object	value)	{
								switch	(name)	{
												case	'house':	return	new	House(attributes)
												case	'roof':	return	new	Roof(attributes	+	[material:	value])
												case	'level':	return	new	Level(floor:	value)
												case	'material':
																return	value	instanceof	Material	?	value	:	Material.valueOf(value.toString())
												default:	return	null
								}
				}
				@Override	protected	void	setParent(Object	parent,	Object	child)	{
								switch	(child)	{
												case	Roof:	parent.roof	=	child;	break
												case	Level:	parent.level	<<	child;	break
												case	Material:	parent.material	=	child;	break
								}
				}
 
38
Using	a	plant
Material	as	a	node
				static	main(def	args)	{
								House	house	=	this.newInstance().house(number:	1)	{
												material('Bricks')
												roof('tiles',	color:	'Red')
												level('1nd	floor')	{}
												level('Ground	floor')	{}
												level('Basement')	{}
								}
								prettyPrint(house)
				}
 
39
Using	a	plant
Building	the	rooms
				@Override	protected	Object	createNode(Object	name,	Map	attributes	=	[:],	Object	value)	{
								switch	(name)	{
												case	'house':	return	new	House(attributes)
												case	'roof':	return	new	Roof(attributes	+	[material:	value])
												case	'level':	return	new	Level(floor:	value)
												case	'material':
																return	value	instanceof	Material	?	value	:	Material.valueOf(value.toString())
												case	'room':
																String	roomName	=	value	?:	attributes.remove('name')
																return	new	Room(attributes	+	[name:	roomName])
												default:	return	null
								}
				}
				@Override	protected	void	setParent(Object	parent,	Object	child)	{
								switch	(child)	{
												case	Roof:	parent.roof	=	child;	break
												case	Level:	parent.level	<<	child;	break
												case	Material:	parent.material	=	child;	break
												case	Room:	parent.rooms	<<	child;	break
								}
				}
 
40
Using	a	plant
Building	the	rooms
				static	main(def	args)	{
								House	house	=	this.newInstance().house(number:	1)	{
												material('Bricks')
												roof('tiles',	color:	'Red')
												level('1nd	floor')	{
																room(name:	'Bedroom')
																room('Childrens	room')
												}
												level('Ground	floor')	{
																room('Living	room')
																room('Kitchen')
												}
												level('Basement')	{
																room('Laundry')
																room('Cellar')	{
																				room('Food	storage')
																				room('Store	room')
																}
												}
								}
								prettyPrint(house)
				}
 
41
Factory	scale
 
42
Factory	scale
groovy.util.FactoryBuilderSupport
 
43
Factory	scale
Scaffolding
All	methods	starting	with	'register'	will	be	executed
Part	after	'register'	is	used	as	group	name
Group	name	is	internally	stored	to	be	queried	in	your	builder
class	Factory	extends	FactoryBuilderSupport	{
				public	Factory(boolean	init	=	true)	{
								super(init)
				}
				def	registerNodes()	{
								registerBeanFactory('house',	House)
				}
				static	main(def	args)	{
								prettyPrint	this.newInstance(true).house(number:	1)
				}
}
 
44
Factory	scale
Roofs
				def	registerNodes()	{
								registerBeanFactory('house',	House)
								registerFactory('roof',	new	RoofFactory())
				}
				static	main(def	args)	{
								prettyPrint	this.newInstance(true).house(number:	1)	{
												roof('tiles',	color:	'Red')
								}
				}
 
45
Factory	scale
RoofFactory
class	RoofFactory	extends	AbstractFactory	{
				@Override
				Object	newInstance(FactoryBuilderSupport	builder,	Object	name,	Object	value,	Map	attributes)
												throws	InstantiationException,	IllegalAccessException	{
								return	new	Roof(material:	attributes.remove('material')	?:	value)
				}
				@Override
				boolean	isLeaf()	{
								true
				}
				@Override
				void	setParent(FactoryBuilderSupport	builder,	Object	parent,	Object	child)	{
								if	(parent	instanceof	House)
												parent.roof	=	child
				}
}
 
46
Factory	scale
Storages
				def	registerNodes()	{
								registerBeanFactory('house',	House)
								registerFactory('roof',	new	RoofFactory())
								registerFactory('level',	new	LevelFactory())
				}
				static	main(def	args)	{
								prettyPrint	this.newInstance(true).house(number:	1)	{
												roof('tiles',	color:	'Red')
												level('1nd	floor')	{}
												level('Ground	floor')	{}
												level('Basement')	{}
								}
				}
 
47
Factory	scale
LevelFactory
class	LevelFactory	extends	AbstractFactory	{
				@Override
				Object	newInstance(FactoryBuilderSupport	builder,	Object	name,	Object	value,	Map	attributes)
												throws	InstantiationException,	IllegalAccessException	{
								return	new	Level(floor:	attributes.remove('floor')	?:	value)
				}
				@Override
				void	setParent(FactoryBuilderSupport	builder,	Object	parent,	Object	child)	{
								if	(parent	instanceof	House)
												parent.level	<<	child
				}
}
 
48
Factory	scale
Material
				def	registerNodes()	{
								registerBeanFactory('house',	House)
								registerFactory('roof',	new	RoofFactory())
								registerFactory('level',	new	LevelFactory())
								registerFactory('material',	new	MaterialFactory())
				}
				static	main(def	args)	{
								prettyPrint	this.newInstance(true).house(number:	1)	{
												material('Bricks')
												roof('tiles',	color:	'Red')
												level('1nd	floor')	{}
												level('Ground	floor')	{}
												level('Basement')	{}
								}
				}
 
49
Factory	scale
MaterialFactory
class	MaterialFactory	extends	AbstractFactory	{
				@Override
				Object	newInstance(FactoryBuilderSupport	builder,	Object	name,	Object	value,	Map	attributes)
												throws	InstantiationException,	IllegalAccessException	{
								return	value	instanceof	Material	?	value	:	Material.valueOf(value)
				}
				@Override
				void	setParent(FactoryBuilderSupport	builder,	Object	parent,	Object	child)	{
								if	(parent	instanceof	House)
												parent.material	=	child
				}
}
 
50
Factory	scale
Building	the	rooms
				def	registerNodes()	{
								registerBeanFactory('house',	House)
								registerFactory('roof',	new	RoofFactory())
								registerFactory('level',	new	LevelFactory())
								registerFactory('material',	new	MaterialFactory())
								registerFactory('room',	new	RoomFactory())
				}
 
51
Factory	scale
Building	the	rooms
				static	main(def	args)	{
								prettyPrint	this.newInstance(true).house(number:	1)	{
												material('Bricks')
												roof('tiles',	color:	'Red')
												level('1nd	floor')	{
																room(name:	'Bedroom')
																room('Childrens	room')
												}
												level('Ground	floor')	{
																room('Living	room')
																room('Kitchen')
												}
												level('Basement')	{
																room('Laundry')
																room('Cellar')	{
																				room('Food	storage')
																				room('Store	room')
																}
												}
								}
				}
 
52
Factory	scale
RoomFactory
class	RoomFactory	extends	AbstractFactory	{
				@Override
				Object	newInstance(FactoryBuilderSupport	builder,	Object	name,	Object	value,	Map	attributes)
												throws	InstantiationException,	IllegalAccessException	{
								return	new	Room((attributes.remove('name')	?:	value)?.toString())
				}
				@Override
				void	setParent(FactoryBuilderSupport	builder,	Object	parent,	Object	child)	{
								if	(parent	instanceof	Level)
												parent.rooms	<<	child
//								else	if	(parent	instanceof	Room)
//												parent.rooms	<<	child
				}
				@Override
				void	setChild(FactoryBuilderSupport	builder,	Object	parent,	Object	child)	{
								if	(child	instanceof	Room)
												parent.rooms	<<	child
				}
}
 
53
Miscellaneous
 
54
Temperature
Collecting	data	externally
				static	main(def	args)	{
								def	builder	=	this.newInstance(true)
								prettyPrint	builder.house(number:	1,	temperature:	60)	{
												material('Bricks')
												roof('tiles',	color:	'Red')
												level('1nd	floor')	{
																room(name:	'Bedroom')	{
																				cooler(-5)
																}
																room('Childrens	room')	{
																				heating(5)
																}
												}
												level('Basement',	temperature:	55)	{
																room('Laundry')
																room('Cellar',	temperature:	50)	{
																				room('Food	storage',	temperature:	40)
																				room('Store	room')
																}
												}
								}
								println	"Room	Temperatures:	$builder.roomTemperature"
				}
 
55
Temperature
Attribute	Delegates
				public	FactoryTemperature(boolean	init	=	true)	{
								super(init)
								setVariable('roomTemperature',	[:])
				}
				def	registerNodes()	{
								registerBeanFactory('house',	House)
								registerFactory('roof',	new	RoofFactory())
								registerFactory('level',	new	LevelFactory())
								registerFactory('material',	new	MaterialFactory())
								registerFactory('room',	new	RoomFactory())
								addAttributeDelegate	{	FactoryBuilderSupport	builder,	Object	node,	Map	attributes	->
												def	temperature	=	attributes.remove	'temperature'
												if	(temperature	instanceof	Number)
																builder.context.temperature	=	temperature
												else	{
																temperature	=	builder.parentContext.temperature
																if	(temperature)
																				builder.context.temperature	=	temperature
												}
								}
				}
 
56
Temperature
Using	transparent	nodes
TemperatureFactory
registerFactory('heating',	new	TemperatureFactory())
registerFactory('cooler',	new	TemperatureFactory())
class	TemperatureFactory	extends	AbstractFactory	{
				@Override
				Object	newInstance(FactoryBuilderSupport	builder,	Object	name,	Object	value,	Map	attributes)
												throws	InstantiationException,	IllegalAccessException	{
								return	[modifier:	value]
				}
				@Override
				void	setParent(FactoryBuilderSupport	builder,	Object	parent,	Object	child)	{
								Number	temperature	=	builder.parentContext.temperature	+	child.modifier
								builder.roomTemperature[parent.name]	=	temperature
				}
}
 
57
Temperature
Result
Room	Temperatures:	[
				Bedroom:55,
				Childrens	room:65,
				Laundry:55,
				Cellar:50,
				Food	storage:40,
				Store	room:50
]
 
58
Ringing	the	bell
Taking	control	over	the	Closure
				registerFactory('bell',	new	BellFactory())
				static	main(def	args)	{
								House	house	=	this.newInstance(true).house(number:	1)	{
												bell	{
																println	"The	door	rings"
												}
												material('Bricks')
												roof('tiles',	color:	'Red')
												level('1nd	floor')	{
																room(name:	'Bedroom')
																room('Childrens	room')
												}
								}
								prettyPrint	house
								house.ring()
				}
 
59
Ringing	the	bell
BellFactory
class	BellFactory	extends	AbstractFactory	{
				@Override
				Object	newInstance(FactoryBuilderSupport	builder,	Object	name,	Object	value,	Map	attributes)
												throws	InstantiationException,	IllegalAccessException	{
								return	[:]
				}
				@Override
				boolean	isLeaf()	{	return	false	}
				@Override
				boolean	isHandlesNodeChildren()	{	true	}
				@Override
				boolean	onNodeChildren(FactoryBuilderSupport	builder,	Object	node,	Closure	childContent)	{
								builder.current.bell	=	childContent
								return	false
				}
}
 
60
Linking	Doors
Door	instance
@Canonical
class	Door	{
				Room	one
				Room	two
}
 
61
Linking	Doors
				static	main(def	args)	{
								prettyPrint	this.newInstance(true).house(number:	1)	{
												level('1nd	floor')	{
																room(name:	'Bedroom')
																room('Childrens	room')	{
																				door('Bedroom')
																}
												}
												level('Ground	floor')	{
																room('Living	room')	{
																				door('Kitchen')
																}
																room('Kitchen')
												}
												level('Basement')	{
																room('Laundry')	{
																				door('Food	storage')
																}
																room('Cellar')	{
																				room('Food	storage')	{
																								door('Laundry')
																				}
																				room('Store	room')	{
																								door('Laundry')
																				}
				}			}			}			}
 
62
Linking	Doors
class	RoomFactory	extends	AbstractFactory	{
				@Override
				Object	newInstance(FactoryBuilderSupport	builder,	Object	name,	Object	value,	Map	attributes)
												throws	InstantiationException,	IllegalAccessException	{
								Room	room	=	new	Room((attributes.remove('name')	?:	value)?.toString())
								getLevelContext(builder).roomMap."$room.name"	=	room
								return	room
				}
				@Override
				void	setParent(FactoryBuilderSupport	builder,	Object	parent,	Object	child)	{
								if	(parent	instanceof	Level)
												parent.rooms	<<	child
				}
				@Override
				void	setChild(FactoryBuilderSupport	builder,	Object	parent,	Object	child)	{
								if	(child	instanceof	Room)
												parent.rooms	<<	child
				}
				Map	getLevelContext(FactoryBuilderSupport	builder)	{
								Map	levelContext	=	builder.parentContext
								while	(levelContext."$FactoryBuilderSupport.CURRENT_NAME"	!=	'level')
												levelContext	=	levelContext."$FactoryBuilderSupport.PARENT_CONTEXT"
								return	levelContext
				}
}
 
63
Linking	Doors
DoorFactory
registerFactory('door',	new	DoorFactory())
class	DoorFactory	extends	AbstractFactory	{
				@Override
				Object	newInstance(FactoryBuilderSupport	builder,	Object	name,	Object	value,	Map	attributes)
												throws	InstantiationException,	IllegalAccessException	{
								return	[from:	value]
				}
				@Override
				void	setParent(FactoryBuilderSupport	builder,	Object	parent,	Object	child)	{
								Map	levelContext	=	builder.parentFactory.getLevelContext(builder)
								Room	other	=	levelContext.roomMap."$child.from"
								if	(other)	{
												Door	door	=	new	Door(other,	parent)
												other.doors	<<	door
												parent.doors	<<	door
								}	else	{
												levelContext.freeDoors."$child.from"	=	parent
								}
				}
}
 
64
Linking	Doors
LevelFactory
class	LevelFactory	extends	AbstractFactory	{
				@Override
				Object	newInstance(FactoryBuilderSupport	builder,	Object	name,	Object	value,	Map	attributes)
												throws	InstantiationException,	IllegalAccessException	{
								builder.context.roomMap	=	[:]
								builder.context.freeDoors	=	[:]
								return	new	Level(floor:	attributes.remove('floor')	?:	value)
				}
				@Override
				void	setParent(FactoryBuilderSupport	builder,	Object	parent,	Object	child)	{
								if	(parent	instanceof	House)	parent.level	<<	child
				}
				@Override
				void	onNodeCompleted(FactoryBuilderSupport	builder,	Object	parent,	Object	node)	{
								builder.context.freeDoors.each	{	String	name,	Room	room	->
												def	other	=	builder.context.roomMap."$name"
												if	(other)	{
																Door	door	=	new	Door(room,	other)
																other.doors	<<	door
																room.doors	<<	door
												}
								}
}			}
 
65
Linking	Doors
Result
{
		<House>	material:	null,	roof:	null,	number:	1
		level			:	[	{
																	<Level>	floor:	1nd	floor,	rooms:	[
																			{	<Room>	name:	Bedroom,	rooms:	[],
																							doors:	[	<Door>	room:	Bedroom,	room:	Childrens	room	]
																			},
																			{
																					<Room>	name:	Childrens	room,	rooms:	[],
																							doors:	[	<Door>	room:	Bedroom,	room:	Childrens	room	]
																			}
																	]
															},
															{
																	<Level>	floor	:	Ground	floor,	rooms:	[
																			{	<Room>	name:	Living	room,	rooms:	[],
																							doors:	[	<Door>	room:	Living	room,	room:	Kitchen	]
																			},
																			{	<Room>	name:	Kitchen,	rooms:	[],
																							doors:	[	<Door>	room:	Living	room,	room:	Kitchen	]
																			}
																	]
															},
 
66
Linking	Doors
Result
															{
																	<Level>	floor:	Basement,	rooms:	[
																			{	<Room>	name:	Laundry,	rooms:	[],
																							doors:	[	<Door>	room:	Laundry,	room:	Food	storage,
																																<Door>	room:	Laundry,	room:	Store	room	]
																			},
																			{	<Room>	name:	Cellar,	rooms:	[
																							{	<Room>	name:	Food	storage,	rooms:	[],
																											doors:	[	<Door>	room:	Laundry,	room:	Food	storage	]
																							},
																							{	<Room>	name:	Store	room,	rooms:	[],
																											doors:	[	<Door>	room:	Laundry,	room:	Store	room	]
																							}
																					],	doors:	[]
																			}
																	]
															}
													]
}
 
67
Untouched
groovy.util.Factory
groovy.util.FactoryBuilderSupport
	
void	onFactoryRegistration(FactoryBuilderSupport	builder,	String	name,	String	groupName)
void	registerExplicitProperty(String	name,	Closure	getter,	Closure	setter)
void	registerExplicitMethod(String	name,	Closure	closure)
Closure	addPreInstantiateDelegate(Closure	delegate)
Closure	addPostInstantiateDelegate(Closure	delegate)
Closure	addPostNodeCompletionDelegate(Closure	delegate)
 
68
Questions?
Alexander	Klein
Branchmanager
codecentric	AG
Curiestr.	2
70563	Stuttgart,	Germany
	+49	(0)	172	529	40	20
	alexander.klein@codecentric.de
	www.codecentric.de
	blog.codecentric.de
	@saschaklein
 
69

More Related Content

Recently uploaded

Abortion Pills For Sale WhatsApp[[+27737758557]] In Birch Acres, Abortion Pil...
Abortion Pills For Sale WhatsApp[[+27737758557]] In Birch Acres, Abortion Pil...Abortion Pills For Sale WhatsApp[[+27737758557]] In Birch Acres, Abortion Pil...
Abortion Pills For Sale WhatsApp[[+27737758557]] In Birch Acres, Abortion Pil...
drm1699
 
Team Transformation Tactics for Holistic Testing and Quality (NewCrafts Paris...
Team Transformation Tactics for Holistic Testing and Quality (NewCrafts Paris...Team Transformation Tactics for Holistic Testing and Quality (NewCrafts Paris...
Team Transformation Tactics for Holistic Testing and Quality (NewCrafts Paris...
Lisi Hocke
 

Recently uploaded (20)

Abortion Pill Prices Jozini ](+27832195400*)[ 🏥 Women's Abortion Clinic in Jo...
Abortion Pill Prices Jozini ](+27832195400*)[ 🏥 Women's Abortion Clinic in Jo...Abortion Pill Prices Jozini ](+27832195400*)[ 🏥 Women's Abortion Clinic in Jo...
Abortion Pill Prices Jozini ](+27832195400*)[ 🏥 Women's Abortion Clinic in Jo...
 
GraphSummit Milan - Neo4j: The Art of the Possible with Graph
GraphSummit Milan - Neo4j: The Art of the Possible with GraphGraphSummit Milan - Neo4j: The Art of the Possible with Graph
GraphSummit Milan - Neo4j: The Art of the Possible with Graph
 
Community is Just as Important as Code by Andrea Goulet
Community is Just as Important as Code by Andrea GouletCommunity is Just as Important as Code by Andrea Goulet
Community is Just as Important as Code by Andrea Goulet
 
Abortion Clinic Pretoria ](+27832195400*)[ Abortion Clinic Near Me ● Abortion...
Abortion Clinic Pretoria ](+27832195400*)[ Abortion Clinic Near Me ● Abortion...Abortion Clinic Pretoria ](+27832195400*)[ Abortion Clinic Near Me ● Abortion...
Abortion Clinic Pretoria ](+27832195400*)[ Abortion Clinic Near Me ● Abortion...
 
A Deep Dive into Secure Product Development Frameworks.pdf
A Deep Dive into Secure Product Development Frameworks.pdfA Deep Dive into Secure Product Development Frameworks.pdf
A Deep Dive into Secure Product Development Frameworks.pdf
 
The mythical technical debt. (Brooke, please, forgive me)
The mythical technical debt. (Brooke, please, forgive me)The mythical technical debt. (Brooke, please, forgive me)
The mythical technical debt. (Brooke, please, forgive me)
 
Alluxio Monthly Webinar | Simplify Data Access for AI in Multi-Cloud
Alluxio Monthly Webinar | Simplify Data Access for AI in Multi-CloudAlluxio Monthly Webinar | Simplify Data Access for AI in Multi-Cloud
Alluxio Monthly Webinar | Simplify Data Access for AI in Multi-Cloud
 
Abortion Clinic In Stanger ](+27832195400*)[ 🏥 Safe Abortion Pills In Stanger...
Abortion Clinic In Stanger ](+27832195400*)[ 🏥 Safe Abortion Pills In Stanger...Abortion Clinic In Stanger ](+27832195400*)[ 🏥 Safe Abortion Pills In Stanger...
Abortion Clinic In Stanger ](+27832195400*)[ 🏥 Safe Abortion Pills In Stanger...
 
GraphSummit Milan - Visione e roadmap del prodotto Neo4j
GraphSummit Milan - Visione e roadmap del prodotto Neo4jGraphSummit Milan - Visione e roadmap del prodotto Neo4j
GraphSummit Milan - Visione e roadmap del prodotto Neo4j
 
Encryption Recap: A Refresher on Key Concepts
Encryption Recap: A Refresher on Key ConceptsEncryption Recap: A Refresher on Key Concepts
Encryption Recap: A Refresher on Key Concepts
 
Abortion Pill Prices Jane Furse ](+27832195400*)[ 🏥 Women's Abortion Clinic i...
Abortion Pill Prices Jane Furse ](+27832195400*)[ 🏥 Women's Abortion Clinic i...Abortion Pill Prices Jane Furse ](+27832195400*)[ 🏥 Women's Abortion Clinic i...
Abortion Pill Prices Jane Furse ](+27832195400*)[ 🏥 Women's Abortion Clinic i...
 
Abortion Clinic In Pretoria ](+27832195400*)[ 🏥 Safe Abortion Pills in Pretor...
Abortion Clinic In Pretoria ](+27832195400*)[ 🏥 Safe Abortion Pills in Pretor...Abortion Clinic In Pretoria ](+27832195400*)[ 🏥 Safe Abortion Pills in Pretor...
Abortion Clinic In Pretoria ](+27832195400*)[ 🏥 Safe Abortion Pills in Pretor...
 
Software Engineering - Introduction + Process Models + Requirements Engineering
Software Engineering - Introduction + Process Models + Requirements EngineeringSoftware Engineering - Introduction + Process Models + Requirements Engineering
Software Engineering - Introduction + Process Models + Requirements Engineering
 
Abortion Pills For Sale WhatsApp[[+27737758557]] In Birch Acres, Abortion Pil...
Abortion Pills For Sale WhatsApp[[+27737758557]] In Birch Acres, Abortion Pil...Abortion Pills For Sale WhatsApp[[+27737758557]] In Birch Acres, Abortion Pil...
Abortion Pills For Sale WhatsApp[[+27737758557]] In Birch Acres, Abortion Pil...
 
Navigation in flutter – how to add stack, tab, and drawer navigators to your ...
Navigation in flutter – how to add stack, tab, and drawer navigators to your ...Navigation in flutter – how to add stack, tab, and drawer navigators to your ...
Navigation in flutter – how to add stack, tab, and drawer navigators to your ...
 
Team Transformation Tactics for Holistic Testing and Quality (NewCrafts Paris...
Team Transformation Tactics for Holistic Testing and Quality (NewCrafts Paris...Team Transformation Tactics for Holistic Testing and Quality (NewCrafts Paris...
Team Transformation Tactics for Holistic Testing and Quality (NewCrafts Paris...
 
Automate your OpenSIPS config tests - OpenSIPS Summit 2024
Automate your OpenSIPS config tests - OpenSIPS Summit 2024Automate your OpenSIPS config tests - OpenSIPS Summit 2024
Automate your OpenSIPS config tests - OpenSIPS Summit 2024
 
Transformer Neural Network Use Cases with Links
Transformer Neural Network Use Cases with LinksTransformer Neural Network Use Cases with Links
Transformer Neural Network Use Cases with Links
 
Anypoint Code Builder - Munich MuleSoft Meetup - 16th May 2024
Anypoint Code Builder - Munich MuleSoft Meetup - 16th May 2024Anypoint Code Builder - Munich MuleSoft Meetup - 16th May 2024
Anypoint Code Builder - Munich MuleSoft Meetup - 16th May 2024
 
Prompt Engineering - an Art, a Science, or your next Job Title?
Prompt Engineering - an Art, a Science, or your next Job Title?Prompt Engineering - an Art, a Science, or your next Job Title?
Prompt Engineering - an Art, a Science, or your next Job Title?
 

Featured

How Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental HealthHow Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental Health
ThinkNow
 
Social Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsSocial Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie Insights
Kurio // The Social Media Age(ncy)
 

Featured (20)

2024 State of Marketing Report – by Hubspot
2024 State of Marketing Report – by Hubspot2024 State of Marketing Report – by Hubspot
2024 State of Marketing Report – by Hubspot
 
Everything You Need To Know About ChatGPT
Everything You Need To Know About ChatGPTEverything You Need To Know About ChatGPT
Everything You Need To Know About ChatGPT
 
Product Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage EngineeringsProduct Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage Engineerings
 
How Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental HealthHow Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental Health
 
AI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdfAI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdf
 
Skeleton Culture Code
Skeleton Culture CodeSkeleton Culture Code
Skeleton Culture Code
 
PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024
 
Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)
 
How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024
 
Social Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsSocial Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie Insights
 
Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024
 
5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary
 
ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd
 
Getting into the tech field. what next
Getting into the tech field. what next Getting into the tech field. what next
Getting into the tech field. what next
 
Google's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentGoogle's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search Intent
 
How to have difficult conversations
How to have difficult conversations How to have difficult conversations
How to have difficult conversations
 
Introduction to Data Science
Introduction to Data ScienceIntroduction to Data Science
Introduction to Data Science
 
Time Management & Productivity - Best Practices
Time Management & Productivity -  Best PracticesTime Management & Productivity -  Best Practices
Time Management & Productivity - Best Practices
 
The six step guide to practical project management
The six step guide to practical project managementThe six step guide to practical project management
The six step guide to practical project management
 
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
 

Bob the Builder - Gr8Conf EU 2017