DI Container на примере bottle.js
Это продолжение заметки Dependecy Injection
Если же развить паттерн Service Locator и представить себе центральный объект, в котором мы будем регистрировать все сервисы и зависимости и в конечном итоге получать центральный объект который и становиться нашей программой то мы получим паттерн DI Container. Здесь я продемонстрирую работу с библиотекой bottle.js как с примером реализации этого паттерна. Если почитать документацию то, как мне показалось, самым обобщённым и понятным подходом будет использование Service Factory
Ну и итог: При правильной модульности программы в ней появляется большое количество логических единиц (классов, объектов, функций) которые в конечном итоге надо собрать и связать с друг другом, все они будут взаимно использоваться в процессе работы и DI Container самая продвинутая техника (Ну, так говорят), при небольшом количестве этих самых подсистем можно и просто вручную создать нужные объекты, импортировать классы и использовать простой коструктор или сеттер, или же использовать Service Locator (глобальный объект со ссылками на все зависимости).
Если же развить паттерн Service Locator и представить себе центральный объект, в котором мы будем регистрировать все сервисы и зависимости и в конечном итоге получать центральный объект который и становиться нашей программой то мы получим паттерн DI Container. Здесь я продемонстрирую работу с библиотекой bottle.js как с примером реализации этого паттерна. Если почитать документацию то, как мне показалось, самым обобщённым и понятным подходом будет использование Service Factory
var bottlejs = require('bottlejs');
let bottle = bottlejs();
class PostDB {
posts = [];
save(post){
this.posts.push(post);
}
getPosts(){
return this.posts;
}
removePost(id){
this.posts = this.posts.filter(post => post.id !== id);
}
getPostsById(id){
return this.posts.filter(post => post.id === id);
}
getPostsByBlogId(id){
return this.posts.filter(post => post.blogId === id);
}
}
class Post{
static id = 0;
constructor(title, message, blogId){
this.id = this.constructor.id++;
this.title = title;
this.message = message;
this.blogId = blogId;
}
}
class PostService{
constructor(postDB, Post){
this.postDB = postDB;
this.Post = Post;
}
addPost(title, message, blogId = 0){
const post = new this.Post(title, message, blogId);
this.postDB.save(post);
return post.id;
}
removePost(postId){
this.postDB.removePost(postId);
}
getPosts(){
return this.postDB.getPosts();
}
getPostsById(id){
return postDB.getPostsById();
}
getPostsByBlogId(id){
return postDB.getPostsByBlogId(id);
}
}
bottle.factory('Post', (container) => Post);
bottle.service('postDB', PostDB); // Service это тот же Factory только возвращает объект переданного класса
bottle.factory('postService', (container) => new PostService(container.postDB, container.Post));
// А это Service вместо Service Factory где все аргументы после второго будут переданны в функцию-конструктор (второй аргумент):
// bottle.service('postService', PostService, 'postDB', 'Post');
bottle.container.postService.addPost('Title', 'Content');
bottle.container.postService.getPosts();
Важный момент это аргумент функции-параметра в методе factory, это объект bottle.container, который хранит в себе все зарегистрированные модули.
Здесь в примере используюется и service который по сути является сахаром вокруг factory. Но я до конца не уверен в том правильно ли я храню класс Post, который я зарегистрировал с помощью Service Factory, но этот подход работает и выглядит нормально. Ну и дальше для удобства выносим bottle.container в отдельную переменную/константу:
const app = bottle.container;
app.postService.addPost('Title', 'Content');
app.postService.getPosts();
Добавлять лоигку работы с блогами я тут не буду, на мой взгляд и так всё понятно.
Ну и итог: При правильной модульности программы в ней появляется большое количество логических единиц (классов, объектов, функций) которые в конечном итоге надо собрать и связать с друг другом, все они будут взаимно использоваться в процессе работы и DI Container самая продвинутая техника (Ну, так говорят), при небольшом количестве этих самых подсистем можно и просто вручную создать нужные объекты, импортировать классы и использовать простой коструктор или сеттер, или же использовать Service Locator (глобальный объект со ссылками на все зависимости).
Комментарии
Отправить комментарий