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 Having a framework that creates and wire components is quite good. In previous tutorials, 13 was explained how to inject compile time known data, and how to reference dependent components, 14 but while designing a framework, or a library in conjunction with AEDI framework, exposing a set 15 of parameters might be desired. 16 To expose a set of configuration parameters, framework provides a special version of container, 17 that stores in those parameters, and serves them to the requestor. To use this container it 18 should be attached to a composite container along the rest of containers, as in previous tutorial and used 19 along them. The process of adding parameters into container is easy as with rest of shown containers, 20 the only difference is, that $(D_INLINECODE register) method doesn’t require an explicit component type, since it 21 is inferred from passed value. Example below shows basic usage of value container: 22 23 -------------------- 24 auto container = aggregate( // Create a joint container hosting other two containers 25 singleton(), "singleton", // Create singleton container, and store it in joint container by "singleton" identity 26 prototype(), "prototype", // Create prototype container, and store it in joint container by "prototype" identity 27 values(), "parameters" // Create value container, and store it in joint container by "prototype" identity 28 ); 29 30 with (container.configure("singleton")) { 31 32 // ... 33 34 } 35 36 with (container.configure("prototype")) { 37 38 // ... 39 } 40 41 with (container.locate!ValueContainer("parameters").configure) { 42 43 register(Size(200, 150, 300), "size.smarty"); 44 } 45 -------------------- 46 47 As seen the configuration for value containers differs from other containers. 48 In case of value containers $(D_INLINECODE configure) method should know exactly 49 what kind of configuration context to create. 50 51 Try running example. Add, modify it to understand usage of containers for already 52 available values. 53 54 License: 55 Boost Software License - Version 1.0 - August 17th, 2003 56 57 Permission is hereby granted, free of charge, to any person or organization 58 obtaining a copy of the software and accompanying documentation covered by 59 this license (the "Software") to use, reproduce, display, distribute, 60 execute, and transmit the Software, and to prepare derivative works of the 61 Software, and to permit third-parties to whom the Software is furnished to 62 do so, all subject to the following: 63 64 The copyright notices in the Software and this entire statement, including 65 the above license grant, this restriction and the following disclaimer, 66 must be included in all copies of the Software, in whole or in part, and 67 all derivative works of the Software, unless such copies or derivative 68 works are solely in the form of machine-executable object code generated by 69 a source language processor. 70 71 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 72 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 73 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 74 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 75 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 76 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 77 DEALINGS IN THE SOFTWARE. 78 79 Authors: 80 aermicioi 81 **/ 82 83 module value_container; 84 85 import aermicioi.aedi; 86 import std.stdio; 87 88 /** 89 A struct that should be managed by container. 90 **/ 91 struct Color { 92 ubyte r; 93 ubyte g; 94 ubyte b; 95 } 96 97 /** 98 Size of a car. 99 **/ 100 struct Size { 101 102 ulong width; 103 ulong height; 104 ulong length; 105 } 106 107 /** 108 Interface for engines. 109 110 An engine should implement it, in order to be installable in a car. 111 **/ 112 interface Engine { 113 114 public { 115 116 void turnOn(); 117 void run(); 118 void turnOff(); 119 } 120 } 121 122 /** 123 A concrete implementation of Engine that uses gasoline for propelling. 124 **/ 125 class GasolineEngine : Engine { 126 127 public { 128 129 void turnOn() { 130 writeln("pururukVrooomVrrr"); 131 132 } 133 134 void run() { 135 writeln("vrooom"); 136 } 137 138 void turnOff() { 139 writeln("vrrrPrrft"); 140 } 141 } 142 } 143 144 /** 145 A concrete implementation of Engine that uses diesel for propelling. 146 **/ 147 class DieselEngine : Engine { 148 149 public { 150 151 void turnOn() { 152 writeln("pururukVruumVrrr"); 153 154 } 155 156 void run() { 157 writeln("vruum"); 158 } 159 160 void turnOff() { 161 writeln("vrrrPft"); 162 } 163 } 164 } 165 166 /** 167 A concrete implementation of Engine that uses electricity for propelling. 168 **/ 169 class ElectricEngine : Engine { 170 public { 171 172 void turnOn() { 173 writeln("pzt"); 174 175 } 176 177 void run() { 178 writeln("vvvvvvvvv"); 179 } 180 181 void turnOff() { 182 writeln("tzp"); 183 } 184 } 185 } 186 187 /** 188 Tire, what it can represent else? 189 **/ 190 class Tire { 191 private { 192 int size_; 193 float pressure_; 194 string vendor_; 195 } 196 197 public @property { 198 Tire size(int size) @safe nothrow { 199 this.size_ = size; 200 201 return this; 202 } 203 204 int size() @safe nothrow { 205 return this.size_; 206 } 207 208 Tire pressure(float pressure) @safe nothrow { 209 this.pressure_ = pressure; 210 211 return this; 212 } 213 214 float pressure() @safe nothrow { 215 return this.pressure_; 216 } 217 218 Tire vendor(string vendor) @safe nothrow { 219 this.vendor_ = vendor; 220 221 return this; 222 } 223 224 string vendor() @safe nothrow { 225 return this.vendor_; 226 } 227 } 228 229 public override string toString() { 230 import std.algorithm; 231 import std.range; 232 import std.conv; 233 import std.utf; 234 235 return only("Tire(", this.size.to!string, " inch, ", this.pressure.to!string, " atm, ", this.vendor, ")") 236 .joiner 237 .byChar 238 .array; 239 } 240 } 241 242 /** 243 A class representing a car. 244 **/ 245 class Car { 246 247 private { 248 Color color_; // Car color 249 Size size_; // Car size 250 Engine engine_; // Car engine 251 252 Tire frontLeft_; 253 Tire frontRight_; 254 Tire backLeft_; 255 Tire backRight_; 256 } 257 258 public { 259 260 /** 261 Constructor of car. 262 263 Constructs a car with a set of sizes. A car cannot of course have 264 undefined sizes, so we should provide it during construction. 265 266 Params: 267 size = size of a car. 268 **/ 269 this(Size size, Engine engine) { 270 this.size_ = size; 271 this.engine = engine; 272 } 273 274 @property { 275 276 /** 277 Set color of car 278 279 Set color of car. A car can live with undefined color (physics allow it). 280 281 Params: 282 color = color of a car. 283 284 Returns: 285 Car 286 **/ 287 Car color(Color color) @safe nothrow { 288 this.color_ = color; 289 290 return this; 291 } 292 293 Color color() @safe nothrow { 294 return this.color_; 295 } 296 297 Size size() @safe nothrow { 298 return this.size_; 299 } 300 301 /** 302 Set engine used in car. 303 304 Params: 305 engine = engine used in car to propel it. 306 307 Returns: 308 Car 309 **/ 310 Car engine(Engine engine) @safe nothrow { 311 this.engine_ = engine; 312 313 return this; 314 } 315 316 Engine engine() @safe nothrow { 317 return this.engine_; 318 } 319 320 Car frontLeft(Tire frontLeft) @safe nothrow { 321 this.frontLeft_ = frontLeft; 322 323 return this; 324 } 325 326 Tire frontLeft() @safe nothrow { 327 return this.frontLeft_; 328 } 329 330 Car frontRight(Tire frontRight) @safe nothrow { 331 this.frontRight_ = frontRight; 332 333 return this; 334 } 335 336 Tire frontRight() @safe nothrow { 337 return this.frontRight_; 338 } 339 340 Car backLeft(Tire backLeft) @safe nothrow { 341 this.backLeft_ = backLeft; 342 343 return this; 344 } 345 346 Tire backLeft() @safe nothrow { 347 return this.backLeft_; 348 } 349 350 Car backRight(Tire backRight) @safe nothrow { 351 this.backRight_ = backRight; 352 353 return this; 354 } 355 356 Tire backRight() @safe nothrow { 357 return this.backRight_; 358 } 359 360 } 361 362 void start() { 363 engine.turnOn(); 364 } 365 366 void run() { 367 engine.run(); 368 } 369 370 void stop() { 371 engine.turnOff(); 372 } 373 } 374 } 375 376 /** 377 A manufacturer of cars. 378 **/ 379 class CarManufacturer { 380 381 public { 382 Car manufacture(Size size) { 383 return new Car(size, new DieselEngine()); // Manufacture a car. 384 } 385 } 386 } 387 388 void drive(Car car, string name) { 389 writeln("Uuh, what a nice car, ", name," with following specs:"); 390 writeln("Size:\t", car.size()); 391 writeln("Color:\t", car.color()); 392 writeln("Engine:\t", car.engine()); 393 writeln("Tire front left:\t", car.frontLeft(), "\t located at memory ", cast(void*) car.frontLeft()); 394 writeln("Tire front right:\t", car.frontRight(), "\t located at memory ", cast(void*) car.frontRight()); 395 writeln("Tire back left: \t", car.backLeft(), "\t located at memory ", cast(void*) car.backLeft()); 396 writeln("Tire back right:\t", car.backRight(), "\t located at memory ", cast(void*) car.backRight()); 397 } 398 399 void main() { 400 auto container = aggregate( // Create a joint container hosting other two containers 401 singleton(), "singleton", // Create singleton container, and store it in joint container by "singleton" identity 402 prototype(), "prototype", // Create prototype container, and store it in joint container by "prototype" identity 403 values(), "parameters" // Create value container, and store it in joint container by "prototype" identity 404 ); 405 406 scope(exit) container.terminate(); 407 408 with (container.configure("singleton")) { 409 410 register!Color; // Let's register a default implementation of Color 411 412 413 register(Color(0, 255, 0), "color.green"); 414 register("divine tire", "tire.vendor"); 415 416 register!Size // Register a size of a generic "sedan" into container 417 .set!"width"(200UL) 418 .set!"height"(150UL) 419 .set!"length"(500UL); 420 421 register!(Engine, ElectricEngine); 422 423 register!Car 424 .autowire 425 .set!"color"("color.green".lref) 426 .set!"frontLeft"(lref!Tire) 427 .set!"frontRight"(lref!Tire) 428 .set!"backLeft"(lref!Tire) 429 .set!"backRight"(lref!Tire); 430 } 431 432 with (container.configure("prototype")) { 433 register!Tire // Registering Tire into "prototype" container used by aggregate container 434 .set!"size"(17) 435 .set!"pressure"(3.0) 436 .set!"vendor"("tire.vendor".lref); 437 } 438 439 with (container.locate!ValueContainer("parameters").configure) { 440 441 register(Size(200, 150, 300), "size.smarty"); 442 } 443 444 container.instantiate(); // Boot container (or prepare managed code/data). 445 446 container.locate!Car.drive("Electric car"); 447 }