The preceding diagram shows the DataDownloader, DataDecoder, and DataDeserializer as composed objects inside DataReader. This is straightforward and clear to achieve—they can be either created with their default constructors, or they can be passed as parameters. For the code representation of our example, however, we have chosen to use traits instead of classes and mix them in with the DataReader class.
Let's first take a look at the DataDownloader, DataDecoder, and DataDeserializer traits:
trait DataDownloader extends LazyLogging { def download(url: String): Array[Byte] = { logger.info("Downloading from: {}", url) Thread.sleep(5000) // { // "name": "Ivan", // "age": 26 // } // the string below is the Base64 encoded Json above. ...