首页 > 其他分享 >Dependency injection framework -- Decoupled packages example (multiple containers) -- ADD DIP IMPROV

Dependency injection framework -- Decoupled packages example (multiple containers) -- ADD DIP IMPROV

时间:2023-12-10 18:33:06浏览次数:29  
标签:multiple repository package -- photo framework analytics user import

Dependency injection framework

https://python-dependency-injector.ets-labs.org/index.html

Dependency Injector is a dependency injection framework for Python.

It helps implementing the dependency injection principle.

Key features of the Dependency Injector:

  • Providers. Provides Factory, Singleton, Callable, Coroutine, Object, List, Dict, Configuration, Resource, Dependency, and Selector providers that help assemble your objects. See Providers.

  • Overriding. Can override any provider by another provider on the fly. This helps in testing and configuring dev/stage environment to replace API clients with stubs etc. See Provider overriding.

Decoupled packages example (multiple containers)

https://python-dependency-injector.ets-labs.org/examples/decoupled-packages.html

This example shows how to use Dependency Injector to create decoupled packages.

To achieve a decoupling each package has a container with the components. When a component needs a dependency from the outside of the package scope we use the Dependency provider. The package container has no knowledge on where the dependencies come from. It states a need that the dependencies must be provided. This helps to decouple a package from the 3rd party dependencies and other packages.

To wire the packages we use an application container. Application container has all 3rd party dependencies and package containers. It wires the packages and dependencies to create a complete application.

We build an example micro application that consists of 3 packages:

  • user - a package with user domain logic, depends on a database

  • photo - a package with photo domain logic, depends on a database and AWS S3

  • analytics - a package with analytics domain logic, depends on the user and photo package components

../_images/decoupled-packages.png

 

DIP abstraction layer to improve

问题

上面例子将每个对象(user photo analytics)设置为一个独立包, 每个包中有对应一个container

从业务逻辑上,对于上层包 analytics 依赖底层包 user 和 photo 的

本例子中, 对于analytics包的依赖做了声明, 仅仅是两个依赖(user_repositories photo_repositories), 但是具体的依赖对象的规格(API)是完全不清楚的

analytics包内是无法调用底层包(user photo)的接口的, 例如在 AggregationService 中调用user和photo接口做数据统计,

所以这里的例子仅仅是依赖性注入展示, 无法应用到实际上项目中。

 

Listing of the example/analytics/containers.py:

"""Analytics containers module."""

from dependency_injector import containers, providers

from . import services


class AnalyticsContainer(containers.DeclarativeContainer):

    user_repository = providers.Dependency()
    photo_repository = providers.Dependency()

    aggregation_service = providers.Singleton(
        services.AggregationService,
        user_repository=user_repository,
        photo_repository=photo_repository,
    )

 

 

改进

对于上下层之间解耦, SOLID设计原则有对应的解法, DIP依赖反转原则,

即上层对象不直接生成和调用下层对象

下层对应对象定义 抽象接口,

上层对象只依赖 抽象接口, 这个接口是上下层之间的合约,供双方遵守,

下层对象按照 抽象接口 实现其自身。

 

https://fanqingsong.github.io/fastapi-hive/design/

 


DIP Definition * High-level cornerstones should not depend on low-level cornerstones. Both should depend on the abstraction. * Abstractions should not depend on details. Details should depend on abstractions.

 

https://github.com/fanqingsong/python-dependency-injector/tree/master/examples/miniapps/decoupled-packages/example

 

 

analytics service abstraction

"""Analytics services module."""

import abc


from ..photo.repositories import PhotoRepositoryMeta
from ..user.repositories import UserRepositoryMeta


class AggregationServiceMeta(metaclass=abc.ABCMeta):

    def __init__(self, user_repository: UserRepositoryMeta, photo_repository: PhotoRepositoryMeta):
        self.user_repository: UserRepositoryMeta = user_repository
        self.photo_repository: PhotoRepositoryMeta = photo_repository

    @abc.abstractmethod
    def call_user_photo(self):
        """Must be implemented in order to instantiate."""
        pass

 

analytics service implementation

"""Analytics services module."""


from ..abstraction.analytics.services import AggregationServiceMeta
from ..abstraction.photo.repositories import PhotoRepositoryMeta
from ..abstraction.user.repositories import UserRepositoryMeta


class AggregationService(AggregationServiceMeta):

    def __init__(self, user_repository: UserRepositoryMeta, photo_repository: PhotoRepositoryMeta):
        self.user_repository: UserRepositoryMeta = user_repository
        self.photo_repository: PhotoRepositoryMeta = photo_repository

    def call_user_photo(self):
        user1 = self.user_repository.get(id=1)
        user1_photos = self.photo_repository.get_photos(user1.id)
        print(f"Retrieve user id={user1.id}, photos count={len(user1_photos)} from aggregation service.")

 

__main__.py (顶层业务实现)

"""Main module."""

from dependency_injector.wiring import Provide, inject

from .abstraction.user.repositories import UserRepositoryMeta
from .abstraction.photo.repositories import PhotoRepositoryMeta
from .abstraction.analytics.services import AggregationServiceMeta

from .containers import ApplicationContainer


@inject
def main(
        user_repository: UserRepositoryMeta = Provide[
            ApplicationContainer.user_package.user_repository
        ],
        photo_repository: PhotoRepositoryMeta = Provide[
            ApplicationContainer.photo_package.photo_repository
        ],
        aggregation_service: AggregationServiceMeta = Provide[
            ApplicationContainer.analytics_package.aggregation_service
        ],
) -> None:
    user1 = user_repository.get(id=1)
    user1_photos = photo_repository.get_photos(user1.id)
    print(f"Retrieve user id={user1.id}, photos count={len(user1_photos)}")

    user2 = user_repository.get(id=2)
    user2_photos = photo_repository.get_photos(user2.id)
    print(f"Retrieve user id={user2.id}, photos count={len(user2_photos)}")

    assert aggregation_service.user_repository is user_repository
    assert aggregation_service.photo_repository is photo_repository
    print("Aggregate analytics from user and photo packages")

    aggregation_service.call_user_photo()


if __name__ == "__main__":
    application = ApplicationContainer()
    application.wire(modules=[__name__])

    main()

 

containers.py (顶层对应组装)

上面三个都是面向抽象接口编程,

具体实例化组装的工作在这里实现。

"""Containers module."""

import sqlite3

import boto3
from dependency_injector import containers, providers

from .user.containers import UserContainer
from .photo.containers import PhotoContainer
from .analytics.containers import AnalyticsContainer


class ApplicationContainer(containers.DeclarativeContainer):

    config = providers.Configuration(ini_files=["config.ini"])

    sqlite = providers.Singleton(sqlite3.connect, config.database.dsn)

    s3 = providers.Singleton(
        boto3.client,
        service_name="s3",
        aws_access_key_id=config.aws.access_key_id,
        aws_secret_access_key=config.aws.secret_access_key,
    )

    user_package = providers.Container(
        UserContainer,
        database=sqlite,
    )

    photo_package = providers.Container(
        PhotoContainer,
        database=sqlite,
        file_storage=s3,
    )

    analytics_package = providers.Container(
        AnalyticsContainer,
        user_repository=user_package.user_repository,
        photo_repository=photo_package.photo_repository,
    )

 

标签:multiple,repository,package,--,photo,framework,analytics,user,import
From: https://www.cnblogs.com/lightsong/p/17893040.html

相关文章

  • SpringBoot实战项目:蚂蚁爱购(从零开发)
    简介这是从零开发的SpringBoot实战项目,名字叫蚂蚁爱购。从零开发项目,视频加文档,十天彻底掌握开发SpringBoot项目。教程路线是:搭建环境=>安装软件=>创建项目=>添加依赖和配置=>通过表生成代码=>编写Java代码=>代码自测=>前后端联调=>准备找工作。学完即可成为合格的Java开发......
  • 算法之快速排序5非递归实现
    一:概述绝大多数的递归逻辑都可以利用栈的方式去代替。代码中一层一层的方法调用,本身就是使用一个方法调用栈。每次进入一个新的方法,就相当于入栈。每次有方法返回就相当于出栈。所以,可以把原本的递归实现转换成一个栈的实现,在栈中存储每一次方法调用的参数。二:具体代码实现/*非......
  • Java IO流(下)
    书接上回:异常完整形态try...catch...引入finally语句块:finally里面的代码一定被执行,除非虚拟机停止。因此释放资源之类的代码非常适合写在finally语句块内。但在关闭前也要判断是否已初始化(是否为null)。importjava.io.FileInputStream;importjava.io.FileOutputStream;importj......
  • # yyds干货盘点 # 盘点一个Pandas处理Excel表格实战问题(下篇)
    大家好,我是皮皮。一、前言继续接着上一篇文章说,这一篇文章我们一起来看看大佬们的解决办法。二、实现过程这里【郑煜哲·Xiaopang】和【瑜亮老师】给了一个提示,如下图所示:后来【隔壁......
  • C++第一课
    之前不太会C++,在leetcode上尝试用C++解决算法问题这里我想使用CLion调试我的C++程序那么问题产生,我该如何创建我的第一个C++项目呢?step1.打开我的CLionso,那么现在我想知道C++Executable和C++Library的区别根据我的编程经验应该不选择C++LibraryC++Executab......
  • 人工智能问题
    人工智能伦理是一个多元的、复杂的领域,涉及科技、社会、哲学、法律等多个方面。在AI技术的发展中,有几个关键的伦理问题值得关注:公平性:AI模型可能会放大已有的社会偏见和歧视。因此,在模型设计和部署过程中,需要关注公平性,确保模型对所有群体都公平对待。透明度:AI模型的决策过程往往难......
  • 再见了Future,图解JDK21虚拟线程的结构化并发
    Java为我们提供了许多启动线程和管理线程的方法。在本文中,我们将介绍一些在Java中进行并发编程的选项。我们将介绍结构化并发的概念,然后讨论Java21中一组预览类——它使将任务拆分为子任务、收集结果并对其进行操作变得非常容易,而且不会不小心留下任何挂起的任务。1基础方法通......
  • centos使用htop查看资源
    环境centos7.9介绍htop是一个用于实时查看和管理系统的进程、内存、CPU使用情况的命令行工具。它提供了一个友好的界面,可以轻松地在终端中监控你的Linux系统。使用安装yuminstallhtop-y如果没有次安装包,更新最新的源yuminstallepel-release-y启动htop3.......
  • 扩展欧几里得算法
    扩欧代码(时间复杂度O(logn))求ax+by=gcd(a,b)的一组整数解 intgcd(inta,intb){ if(b==0)returna; returngcd(b,a%b);}intexgcd(inta,intb,int&x,int&y){ if(b==0) { x=1,y=0; returna; } intx1,y1,d; d=exgcd(b,a%b,x1,y1); x=y1,y=x1-a/b*y1; re......
  • 第三周进展
    本周计划完成任务最后一周了,计划完成全部任务,比如对协议的分析,对协议类型的展示本周实际完成任务实际完成:对握手协议的分析localfunctiondissectHandshake(buffer,pkt,tree)localhandshakeType=buffer(5,1):uint()pkt.cols.protocol:set("TLS-Handshake")......