1 /**
2 Aedi, a dependency injection library.
3 4 Aedi is a dependency injection library. It does provide a set of containers that do
5 IoC, and an interface to configure application components (structs, objects, etc.)
6 7 Aim:
8 9 The aim of library is to provide a dependency injection solution that is
10 feature rich, easy to use, easy to learn, and easy to extend up to your needs.
11 12 In most simple applications, a single container, like singleton or prototype one might be enough,
13 for using. Having a set of singletons constructed on behalf of a developer is convenient, yet there
14 are occurences a single container is not enough. For example when, a set of components rely on a
15 particular dependency, and more specifically, the dependency they rely upon, should not be shared
16 across reliant components. In another case, a set of components are stored in a database, in serialized
17 form, and they are used as dependencies for other components from application.
18 19 In such cases use of a single container like singleton or prototype is not enough, since one set
20 of components should be created by using normal frameworks means, and another set needs to be
21 fetched from a database, or should not be shared to all dependent components. To solve this problem,
22 AEDI framework, allows container to be joined and used together, for creation of components. A
23 component in such a joint container, having a dependency on a prototype component, will have it’s
24 requirement fullfilled without a problem.
25 26 Using as an example car simulation app, the company decided to add a set ”tires” to simulated
27 cars. For a particular car, each tire installed in it has same properties as other installed in same car.
28 Registering 4 times same tire is not cost effective. Instead of it, it is better to register component
29 into a prototype container and use component to supply 4 instances of a tire to a particular car.
30 Example below shows how two or more containers can be joined together, configured with components,
31 and used to instantiate required components.
32 ----------------
33 auto container = aggregate( // Create a joint container hosting other two containers
34 singleton(), "singleton", // Create singleton container, and store it in joint container by "singleton" identity
35 prototype(), "prototype" // Create prototype container, and store it in joint container by "prototype" identity
36 );
37 38 with (container.configure("singleton")) { // Configure singleton container
39 40 // ...
41 42 register!Car
43 .autowire
44 .autowire!"color"
45 .set!"frontLeft"(lref!Tire)
46 .set!"frontRight"(lref!Tire)
47 .set!"backLeft"(lref!Tire)
48 .set!"backRight"(lref!Tire);
49 }
50 51 with (container.configure("prototype")) { // Configure prototype container
52 53 register!Tire // Registering Tire into "prototype" container used by aggregate container
54 .set!"size"(17)
55 .set!"pressure"(3.0)
56 .set!"vendor"("divine tire");
57 }
58 59 //...
60 ----------------
61 To join one or more containers together, an aggregate container must be created that will host
62 both of them under the hood. Once aggregate container has all of joint containers registered in it,
63 the process of registering components takes place.
64 To register components in joint container, pass the identity of subcontainer (container in joint container)
65 to $(D_INLINECODE configure) as an argument, and register components for selected subcontainer.
66 The $(D_INLINECODE configure) function applied to joint container in $(D_INLINECODE with ()) statement
67 creates a configuration context, that stores the container where components are stored, and
68 container from which dependencies for those components should be fetched.
69 In case of joint container, and singleton subcontainer, singleton subcontainer acts as storage while
70 joint container is used as source for dependencies of registered components.
71 72 In the result, the car simulator will be able to use a car, that has 4 different instances of a tire.
73 Output below shows the constructed car by joint containers.
74 -----------------
75 Uuh, what a nice car, Electric car with following specs:
76 Size: Size(200, 150, 300)
77 Color: Color(0, 0, 0)
78 Engine: app.ElectricEngine
79 Tire front left: Tire(17 inch, 3 atm, divine tire) located at memory 7FB560C31180
80 Tire front right: Tire(17 inch, 3 atm, divine tire) located at memory 7FB560C311C0
81 Tire back left: Tire(17 inch, 3 atm, divine tire) located at memory 7FB560C31200
82 Tire back right: Tire(17 inch, 3 atm, divine tire) located at memory 7FB560C31240
83 -----------------
84 85 Notice that each tire is a different object, hence everything is working as we
86 expected!
87 88 Try this example, modify it, play with it to understand how compositing can
89 help in designing your application.
90 91 License:
92 Boost Software License - Version 1.0 - August 17th, 2003
93 94 Permission is hereby granted, free of charge, to any person or organization
95 obtaining a copy of the software and accompanying documentation covered by
96 this license (the "Software") to use, reproduce, display, distribute,
97 execute, and transmit the Software, and to prepare derivative works of the
98 Software, and to permit third-parties to whom the Software is furnished to
99 do so, all subject to the following:
100 101 The copyright notices in the Software and this entire statement, including
102 the above license grant, this restriction and the following disclaimer,
103 must be included in all copies of the Software, in whole or in part, and
104 all derivative works of the Software, unless such copies or derivative
105 works are solely in the form of machine-executable object code generated by
106 a source language processor.
107 108 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
109 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
110 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
111 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
112 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
113 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
114 DEALINGS IN THE SOFTWARE.
115 116 Authors:
117 aermicioi
118 **/119 120 modulemultiple_containers;
121 122 importaermicioi.aedi;
123 importstd.stdio;
124 125 /**
126 A struct that should be managed by container.
127 **/128 structColor {
129 ubyter;
130 ubyteg;
131 ubyteb;
132 }
133 134 /**
135 Size of a car.
136 **/137 structSize {
138 139 ulongwidth;
140 ulongheight;
141 ulonglength;
142 }
143 144 /**
145 Interface for engines.
146 147 An engine should implement it, in order to be installable in a car.
148 **/149 interfaceEngine {
150 151 public {
152 153 voidturnOn();
154 voidrun();
155 voidturnOff();
156 }
157 }
158 159 /**
160 A concrete implementation of Engine that uses gasoline for propelling.
161 **/162 classGasolineEngine : Engine {
163 164 public {
165 166 voidturnOn() {
167 writeln("pururukVrooomVrrr");
168 169 }
170 171 voidrun() {
172 writeln("vrooom");
173 }
174 175 voidturnOff() {
176 writeln("vrrrPrrft");
177 }
178 }
179 }
180 181 /**
182 A concrete implementation of Engine that uses diesel for propelling.
183 **/184 classDieselEngine : Engine {
185 186 public {
187 188 voidturnOn() {
189 writeln("pururukVruumVrrr");
190 191 }
192 193 voidrun() {
194 writeln("vruum");
195 }
196 197 voidturnOff() {
198 writeln("vrrrPft");
199 }
200 }
201 }
202 203 /**
204 A concrete implementation of Engine that uses electricity for propelling.
205 **/206 classElectricEngine : Engine {
207 public {
208 209 voidturnOn() {
210 writeln("pzt");
211 212 }
213 214 voidrun() {
215 writeln("vvvvvvvvv");
216 }
217 218 voidturnOff() {
219 writeln("tzp");
220 }
221 }
222 }
223 224 /**
225 Tire, what it can represent else?
226 **/227 classTire {
228 private {
229 intsize_;
230 floatpressure_;
231 stringvendor_;
232 }
233 234 public @property {
235 Tiresize(intsize) @safenothrow {
236 this.size_ = size;
237 238 returnthis;
239 }
240 241 intsize() @safenothrow {
242 returnthis.size_;
243 }
244 245 Tirepressure(floatpressure) @safenothrow {
246 this.pressure_ = pressure;
247 248 returnthis;
249 }
250 251 floatpressure() @safenothrow {
252 returnthis.pressure_;
253 }
254 255 Tirevendor(stringvendor) @safenothrow {
256 this.vendor_ = vendor;
257 258 returnthis;
259 }
260 261 stringvendor() @safenothrow {
262 returnthis.vendor_;
263 }
264 }
265 266 publicoverridestringtoString() {
267 importstd.algorithm;
268 importstd.range;
269 importstd.conv;
270 importstd.utf;
271 272 returnonly("Tire(", this.size.to!string, " inch, ", this.pressure.to!string, " atm, ", this.vendor, ")")
273 .joiner274 .byChar275 .array;
276 }
277 }
278 279 /**
280 A class representing a car.
281 **/282 classCar {
283 284 private {
285 Colorcolor_; // Car color286 Sizesize_; // Car size287 Engineengine_; // Car engine288 289 TirefrontLeft_;
290 TirefrontRight_;
291 TirebackLeft_;
292 TirebackRight_;
293 }
294 295 public {
296 297 /**
298 Constructor of car.
299 300 Constructs a car with a set of sizes. A car cannot of course have
301 undefined sizes, so we should provide it during construction.
302 303 Params:
304 size = size of a car.
305 **/306 this(Sizesize, Engineengine) {
307 this.size_ = size;
308 this.engine = engine;
309 }
310 311 @property {
312 313 /**
314 Set color of car
315 316 Set color of car. A car can live with undefined color (physics allow it).
317 318 Params:
319 color = color of a car.
320 321 Returns:
322 Car
323 **/324 Carcolor(Colorcolor) @safenothrow {
325 this.color_ = color;
326 327 returnthis;
328 }
329 330 Colorcolor() @safenothrow {
331 returnthis.color_;
332 }
333 334 Sizesize() @safenothrow {
335 returnthis.size_;
336 }
337 338 /**
339 Set engine used in car.
340 341 Params:
342 engine = engine used in car to propel it.
343 344 Returns:
345 Car
346 **/347 Carengine(Engineengine) @safenothrow {
348 this.engine_ = engine;
349 350 returnthis;
351 }
352 353 Engineengine() @safenothrow {
354 returnthis.engine_;
355 }
356 357 CarfrontLeft(TirefrontLeft) @safenothrow {
358 this.frontLeft_ = frontLeft;
359 360 returnthis;
361 }
362 363 TirefrontLeft() @safenothrow {
364 returnthis.frontLeft_;
365 }
366 367 CarfrontRight(TirefrontRight) @safenothrow {
368 this.frontRight_ = frontRight;
369 370 returnthis;
371 }
372 373 TirefrontRight() @safenothrow {
374 returnthis.frontRight_;
375 }
376 377 CarbackLeft(TirebackLeft) @safenothrow {
378 this.backLeft_ = backLeft;
379 380 returnthis;
381 }
382 383 TirebackLeft() @safenothrow {
384 returnthis.backLeft_;
385 }
386 387 CarbackRight(TirebackRight) @safenothrow {
388 this.backRight_ = backRight;
389 390 returnthis;
391 }
392 393 TirebackRight() @safenothrow {
394 returnthis.backRight_;
395 }
396 397 }
398 399 voidstart() {
400 engine.turnOn();
401 }
402 403 voidrun() {
404 engine.run();
405 }
406 407 voidstop() {
408 engine.turnOff();
409 }
410 }
411 }
412 413 /**
414 A manufacturer of cars.
415 **/416 classCarManufacturer {
417 418 public {
419 Carmanufacture(Sizesize) {
420 returnnewCar(size, newDieselEngine()); // Manufacture a car.421 }
422 }
423 }
424 425 voiddrive(Carcar, stringname) {
426 writeln("Uuh, what a nice car, ", name," with following specs:");
427 writeln("Size:\t", car.size());
428 writeln("Color:\t", car.color());
429 writeln("Engine:\t", car.engine());
430 writeln("Tire front left:\t", car.frontLeft(), "\t located at memory ", cast(void*) car.frontLeft());
431 writeln("Tire front right:\t", car.frontRight(), "\t located at memory ", cast(void*) car.frontRight());
432 writeln("Tire back left: \t", car.backLeft(), "\t located at memory ", cast(void*) car.backLeft());
433 writeln("Tire back right:\t", car.backRight(), "\t located at memory ", cast(void*) car.backRight());
434 }
435 436 voidmain() {
437 autocontainer = aggregate( // Create a joint container hosting other two containers438 singleton(), "singleton", // Create singleton container, and store it in joint container by "singleton" identity439 prototype(), "prototype"// Create prototype container, and store it in joint container by "prototype" identity440 );
441 442 scope(exit) container.terminate();
443 444 with (container.configure("singleton")) { // Configure singleton container445 register!Color; // Let's register a default implementation of Color446 447 register!Color("color.green") // Register "green" color into container.448 .set!"r"(cast(ubyte) 0)
449 .set!"g"(cast(ubyte) 255)
450 .set!"b"(cast(ubyte) 0);
451 452 register!Size// Let's register default implementation of a Size453 .set!"width"(200UL)
454 .set!"height"(150UL)
455 .set!"length"(300UL);
456 457 register!Size("size.sedan") // Register a size of a generic "sedan" into container458 .set!"width"(200UL)
459 .set!"height"(150UL)
460 .set!"length"(500UL);
461 462 register!(Engine, ElectricEngine);
463 464 register!Car465 .autowire466 .autowire!"color"467 .set!"frontLeft"(lref!Tire)
468 .set!"frontRight"(lref!Tire)
469 .set!"backLeft"(lref!Tire)
470 .set!"backRight"(lref!Tire);
471 }
472 473 with (container.configure("prototype")) { // Configure prototype container474 475 register!Tire// Registering Tire into "prototype" container used by aggregate container476 .set!"size"(17)
477 .set!"pressure"(3.0)
478 .set!"vendor"("divine tire");
479 }
480 481 container.instantiate(); // Boot container (or prepare managed code/data).482 483 container.locate!Car.drive("Electric car");
484 }