-
Notifications
You must be signed in to change notification settings - Fork 37
task_container
Сдача до 28.03 (20 баллов)
Пакет в репозитории track.container
В соответствие с принципом внедрения зависимостей, при инициализации класса его компоненты должны быть внедрены снаружи через конструктор или с помощью геттеров.
Классы содержат поля, которые могут быть примитивными типами или ссылками на объекты других классов (зависимости). Пусть есть конфигурация, описывающая все объекты, нужные в приложении и их зависимости. Тогда прочитав конфигурацию и распарсив ее, мы получим полную информацию об объектах в нашей программе. На основании этой информации можно создавать запрашиваемые объекты. Такой инструмент называется контейнер объектов.
Для проекта с классами
class Car
class Engine
class Gear
Задан конфиг в формате JSON
src/main/resources/config.json
Можно использовать вариант в xml, который будет выглядеть так:
##XML
<root>
<bean id="carBean" class="track.container.beans.Car">
<property name="gear" ref="gearBean"/>
<property name="engine" ref="engineBean"/>
</bean>
<bean id="gearBean" class="track.container.beans.Gear">
<property name="count" val="6"/>
</bean>
<bean id="engineBean" class="track.container.beans.Engine">
<property name="power" val="200"/>
</bean>
</root>
-
root - корневой элемент конфига
-
bean - описание экземпляра класса (его полей)
- id - уникальное имя экземпляра
- class - определяет класс объекта
-
property - описание конкретного поля
- name - имя свойства, должно совпадать с именем поля класса
- val - примитивное значение, или
- ref - поле ссылается на другой объект
Этот конфиг эквивалентен такому коду:
Gear gear = new Gear();
gear.setCount(6);
Engine engine = new Engine();
engine.setPower(200);
Car car = new Car();
car.setEngine(engine);
car.setPower(power);
Для чтения конфига в формате Json будем использовать библиотеку Jackson Туториалы, примеры: http://www.studytrails.com/java/json/jackson-create-json/ http://www.journaldev.com/2324/jackson-json-java-parser-api-example-tutorial
Пример чтения конфига в src/main/java/track/lections/lection4
XML парсится встроенными стредствами Java https://javaswing.wordpress.com/2010/03/14/java_dom_xml/
- Даны классы в пакете container: ValueType, Bean, Property. Написать класс-реализацию ConfigReader, который прочитает заданный конфиг файл, распарсит его и создаст список beans, соответствующий конфигу.
public class ConfigReader {
// чтение конфига с помощью библиотеки Jackson
public List<Bean> readConfig(String pathToConfigFile) {
return null;
}
}
- Инстанцирование бинов После чтения полного конфига с помощью механизма reflection нужно инстанцировать наши объекты.
Ключевой класс - Container
package track.container;
public class Container {
private List<Bean> beans;
/**
* Если не получается считать конфиг, то бросьте исключение
* @throws InvalidConfigurationException - неверный конфиг
*/
public Container(String pathToConfig) throws InvalidConfigurationException {
}
/**
* Вернуть объект по имени бина из конфига
* Например, Car car = (Car) container.getByName("carBean")
*/
public Object getByName(String name) {
return null;
}
/**
* Вернуть объект по имени класса
* Например, Car car = (Car) container.getByClass("track.container.beans.Car")
*/
public Object getByClass(String className) {
return null;
}
}
Пример использования в коде
Container container = new Container("config.json");
Car car = (Car) container.getByClass("track.container.beans.Car");
Договоримся, что у классов, которые создаются таким образом есть пустой конструктор, его поля - приватные, но имеют методы get/set (обратите внимание на именование метода, это важно):
public class Gear {
private int count;
public Gear() {
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
}
Если valueType == REF, то это означает, что поле ссылочного значения, ему нужно передать ссылку на бин с заданным именем. Если == VAL - то это значит, что поле примитивного типа. Нужно распознать примитивный тип поля и правильно сконверить значение из конфига. Тип поля можно определить по информации из объекта Class, соответствующего бина.
-
Получить список бинов (распарсить конфиг)
-
При запросе бина по имени или по классу, если такого бина еще не создано
a. Вызывать дефолтный конструктор
b. Проходить по Property и устанавливать в поля соответствующие значения. Если объект, который запрашивается в ref еще не создан, то нужно его создать. Также тут нужно обработать ситуацию, когда возникает циклическая зависимость между объектами (то есть для создания объекта A требуется объект Б, а для создания Б - объект А)
c. Созданный объект сохранять Container в Map<String, Object> objByName (маппинг ИмяБина->Объект) и в Map<String, Object> objByClassName (маппинг ИмяКласса -> Объект )
d. Если такой бин уже создан, то просто вернуть его (Все бины - синглтоны!)
-
Для установки значения в поле вызывать метод set<ИмяПоля> (то есть через reflection получить объект Method для установки конкретного поля)