4.架构及分层规范
架构及分层图
如上所示:
myddd-electron架构整体分为以下层:
- 视图模型层
- 应用层
- 领域层
- 基础设施层(含网络,数据库,缓存等)
依赖注入
我们明确规定:使用依赖注入来注入各层的服务
iOC框架使用的是tsyringe
申明依赖注入
@injectable()
export class BlogNet {
}
如上所示,对于申明依赖注入非常简单,只需要在类前使用@injectable()
就可以了。
如果希望以单例的模式注入,使用@singleton()
来注入
注入依赖
方式一 : 使用@Inject注入
@injectable()
export class BlogNet {
private request: BaseRequest;
constructor(@inject(BaseRequest) baseRequest: BaseRequest) {
this.request = baseRequest;
}
}
使用constructor
构建函数方式来申明流入
方式二: 使用getInstance获取实例
export interface IBlog {
private static blogNet: BlogNet;
private static getBlogNet(): BlogNet {
if (!this.blogNet) {
this.blogNet = InstanceFactory.getInstance(BlogNet);
}
return this.blogNet;
}
private static blogRepository: BlogRepository;
private static getBlogRepository(): BlogRepository {
if (!this.blogRepository) {
this.blogRepository = InstanceFactory.getInstance(BlogRepository);
}
return this.blogRepository;
}
}
第二种方式,使用InstanceFactory
的方式来获取依赖。
视图层
此层对应React tsx文件。
参照示例
const BlogContent = observer(() => {
const [content, setContent] = useState("# loading");
const blogStore = useContext(BlogStore);
useEffect(() => {
fetchContent();
}, [blogStore.blog]);
const blogApplication: BlogApplication = InstanceFactory.getInstance(BlogApplication);
const fetchContent = async () => {
if (blogStore.blog) {
const content = await blogApplication.fetchBlogContent(blogStore.blog);
setContent((prev) => content);
}
};
return (
<Layout index={false}>
</Layout>
);
});
export default BlogContent;
视图层不能有业务上的逻辑,其业务逻辑需要全部封装到服务层中去
应用层
应用层为视图层提供服务。
应用层实现
import { Blog } from "modules/blogs/domain/Blog";
import { FileUtil } from "components/util/FileUtil";
import { FSDirUtil } from "components/util/FSDirUtil";
import { injectable } from "tsyringe";
@injectable()
export class BlogApplication {
public fetchLastestBlogs(): Promise<Blog[]> {
return Blog.fetchLastestBlogs();
}
public async fetchMoreBlogs(): Promise<Blog[]> {
return Blog.fetchMoreBlogs();
}
public async fetchBlogContent(blog: Blog): Promise<string> {
const blogFilePath = FSDirUtil.filePath(blog.slug);
const exists = await FileUtil.accessFile(blogFilePath);
if (!exists) {
const content = await blog.fetchContent();
await FileUtil.writeContentToFile(blogFilePath, content);
}
return (await FileUtil.contentOfFile(blogFilePath)).toString("utf-8");
}
}
服务层需调用领域层或缓存等基础设施层
领域层
将领域的一些业务逻辑封装在领域层中,提供给应用层调用。
export class Blog {
private static blogNet: BlogNet;
private static getBlogNet(): BlogNet {
if (!this.blogNet) {
this.blogNet = InstanceFactory.getInstance(BlogNet);
}
return this.blogNet;
}
private static blogRepository: BlogRepository;
private static getBlogRepository(): BlogRepository {
if (!this.blogRepository) {
this.blogRepository = InstanceFactory.getInstance(BlogRepository);
}
return this.blogRepository;
}
/**
* 获取更多博客
* @returns 返回博客列表
*/
public static async fetchMoreBlogs(): Promise<Blog[]> {
const last = await Blog.getBlogRepository().fetchMaxBlogDate();
const blogs = await Blog.getBlogNet().fetchMoreBlogs(last);
await Blog.getBlogRepository().batchSaveBlogs(blogs);
return blogs;
}
public static async fetchLastestBlogs(): Promise<Blog[]> {
return Blog.getBlogRepository().fetchLatestBlogs();
}
public fetchContent(): Promise<string> {
return Blog.getBlogNet().fetchBlogContent(this.slug);
}
}
如上,领域层需要依赖仓储接口及网络接口,将领域的行为封装在领域对象中。
基础设施层
仓储
提供对象数据存储及获取,查询功能。
myddd-electron数据库基于SQLITE3,项目基于SQLITE3封装了相关API。具体查看相关规范
仓储实现
@injectable()
export class BlogRepository {
private repository: Repository;
constructor(@inject(Repository) repository: Repository) {
this.repository = repository;
}
async fetchMaxBlogDate(): Promise<number> {
const sql = "select max(created) as _created from blog_";
const response = await this.repository.executeSingleQuery<IBlog>(sql);
if (response._created == null) return 0;
return response._created;
}
async fetchLatestBlogs(): Promise<Blog[]> {
const sql = "select * from blog_ order by created desc";
const results: IBlog[] = await this.repository.executeQuery<IBlog>(sql);
const blogs: Blog[] = [];
results.forEach((blog) => {
const tags: string[] = blog.tagData.split(",");
blog.tags = tags;
blogs.push(new Blog(blog));
});
return blogs;
}
}
网络
网络实现层
@injectable()
export class BlogNet {
private request: BaseRequest;
constructor(@inject(BaseRequest) baseRequest: BaseRequest) {
this.request = baseRequest;
}
public async fetchBlogContent(slug: string): Promise<string> {
const fetchUrl =
Config.getInstance().api +
"/api/collections/get/blogs?token=" +
Config.getInstance().accessToken;
const parmas = {
filter: {
slug: slug,
},
fields: {
content: 1,
},
};
const response = await this.request.requestForPost(fetchUrl, parmas);
if (response.resultSuccess()) {
const entries: any[] = response.data.entries;
return entries[0].content;
} else {
return "";
}
}
}
缓存
客户端程序,为提升速度,需在关键数据地方使用缓存,以提升体验。
myddd-electron封装了缓存的实现,简化开发
缓存接口
export interface ICache {
/**
* 存储对象到CACHE中
* @param key
* @param data
*/
setData(key:string,data:any):void;
/**
* 从CACHE中获取数据
* @param key
*/
getData(key:string):any;
/**
* 查询指定的KEY是否存在
* @param key
*/
exists(key:string):boolean;
/**
* 清除指定KEY的缓存
* @param key
*/
clearData(key:string):void;
/**
* 清除所有缓存
*/
clearAll():void;
}