前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >工厂方法模式实现权限管理?Python实例详解

工厂方法模式实现权限管理?Python实例详解

作者头像
用户8949263
发布2022-04-08 14:11:12
5830
发布2022-04-08 14:11:12
举报
文章被收录于专栏:Python数据分析实例

上一篇文章分享了简单工厂模式的使用,在运行时根据客户端传入的参数类型来创建相应的实例。本节进一步讨论简单工厂的变体工厂方法模式。

工厂方法模式:是一种创建型设计模式,向客户端开放一个创建对象的方法,使用继承和子类来决定创建哪个对象。工厂方法用于创建单个产品。

1、具有更大的灵活性,使得代码更加通用。实现哪些类取决于接口,而不是具体产品类。

2、工厂方法将创建对象的代码与实际使用它的代码是分开的,松耦合的,从而能在不影响其他代码情况下扩展产品创建部分代码。添加新类变得更加容易,降低了维护成本。

可使用工厂方法模式应用场景

1、编写代码初期版本过程中,如果无法预知对象确切类别及其依赖关系。

2、二次开发,继承重写方法,扩展模块或框架的内部组件。

3、复用现有对象节省系统资源,而不是每次重新创建对象。

4、对象池管理及权限管理。

工厂方法模式类图

←工厂方法模式类图→

1、产品(Product):对接口进行定义。

2、具体产品(ConcreteProduct):产品接口的不同实现。

3、创建者类(Creator):申明返回产品对象的工厂方法。可以将工厂方法声明为抽象方法,强制要求每个子类以不同方式实现该方法。

4、具体创建者(ConcreteCreator):将会重写基础工厂方法,使其返回不同类型的产品。注:并不一定每次调用工厂方法都会创建新的实例,工厂方法可以返回缓存、对象池的已有对象。

工厂方法模式

本次分享结合深圳市便民核酸点服务状态查询服务数据示例。继上篇文章对应用服务端代码进一步优化设计模式。仅需修改以下代码部分。

1)、定义一个接口来创建对象,但是工厂本身并不负责创建对象,而是将该任务交由子类来完成,即子类决定了要实例化哪些类;

2)、Factory方法的创建是通过继承而不是通过实例化来完成;

3)、工厂方法使得设计更加具有可定制性。

1、应用服务端-Map_Load.py

代码语言:javascript
复制
import pandas as pd
import folium
from folium import plugins
from abc import ABCMeta,abstractmethod

#基础底图部分
class Basemap_Section(metaclass=ABCMeta):
    """
    地图初始化基类
    """
    def __init__(self):
        #加载地图模式
        self.Map = folium.Map(location=[22.540477, 114.061226],
                         tiles='https://wprd01.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=1&scl=1&style=7',
                         attr='高德-常规图',
                         zoom_start=10,
                         control_scale=True,
                         width='100%',)

    @abstractmethod
    def execute(self):
        pass


#标记卡片部分
class Card_Section(Basemap_Section):

    def execute(self,data):
        import base64
        encoded = base64.b64encode(open(r'F:\BuildEnergyDataHub_Admin\resources\qrcode_logo.JPG', 'rb').read()).decode()

        # data映射一列数据【color】---设置数据过滤层
        for name, row in data.iterrows():
            html = '<h2> 欢迎关注Python数据分析实例</h2><img src="data:image/jpeg;base64,{0}"><br><h3>采样点名称:{1}</h3>' \
                   '<h3>当前等待时间:{2}</h3><h3>服务时间:{3}</h3><h3>服务人群:{4}</h3>' \
                   '<a href = https://szwj.borycloud.com/wh5/index.html#/>查询服务➡</a>'.format(encoded,row['service_name'],str(row["delay"]),row['service_time'],row['services'])
            iframe = folium.IFrame(html, width=380, height=560)

        return iframe

#地图一次性全加载标记
class Full_Load_Section(Basemap_Section):
    """
   地图一次性全加载
    """
    def execute(self,data,iframe):
        for name, row in data.iterrows():
            folium.Marker(
                [row["LATITUDE"], row["LONGITUDE"]],
                # max_width设置每行显示字符数
                popup=folium.Popup(iframe,
                                   max_width='100%'),  # 备注掉线天数
                tooltip=row["service_name"],
                icon=folium.Icon(icon='info-sign', color=row["color"])).add_to(self.Map)
        print("地图成功生成!")
        return self.Map
        
#地图缩放加载标记
class Zoom_Loading_Section(Basemap_Section):
    """
    地图缩放加载
    """
    def execute(self,data,iframe):
        # 调用Marker可以创建标记,传入位置和信息,当鼠标放在标记上会显示出信息。
        folium.Marker([22.540477,114.061226],
                      popup=folium.Popup("深圳市", max_width=100)).add_to(self.Map)   #创建中心标记

        marker_cluster = plugins.MarkerCluster().add_to(self.Map)

        for name, row in data.iterrows():
            folium.Marker([row["LATITUDE"], row["LONGITUDE"]],
                          popup=folium.Popup(iframe, max_width='100%'),
                          tooltip=row["service_name"],
                          icon=folium.Icon(icon='info-sign', color='lightblue')).add_to(marker_cluster)
        print("地图成功生成")
        return self.Map

#其他功能模块
class Other_Section(Basemap_Section):
    def execute(self):
        # print('Other Section')
        return 'Other Section'

上篇文章简单工厂模式创建了Full_Load和Zoom_Loading两种地图显示产品,包含重复代码部分,对于产品中某些特定的组成部分比如都有一个加载显示卡片区Card_Section类,我们可以进一步细化对方法层面的封装,让每一个功能类尽可能简单独立,将应用封装成具体产品类,然后通过具体产品工厂类继承加载实例化具体的工厂方法实现。

代码语言:javascript
复制
#抽象工厂类Creator
class Map_Profile(metaclass=ABCMeta):
    def __init__(self):
        self.sections = []
        self.createPrfile()

    @abstractmethod
    def createPrfile(self):
        pass

    def getSections(self):
        return self.sections

    def addSections(self,section):
        self.sections.append(section)

#具体工厂类
class Full_Load(Map_Profile):
    """
   地图一次性全加载
    """
    def __init__(self,data):
        super(Full_Load, self).__init__()
        #公共部分
        self.data = data

    def createPrfile(self):
        self.addSections(Card_Section())
        self.addSections(Full_Load_Section())

class Zoom_Loading(Map_Profile):
    """
    地图缩放加载
    """
    def __init__(self,data):
        super(Zoom_Loading, self).__init__()
        #公共部分
        self.data = data

    def createPrfile(self):
        self.addSections(Card_Section())
        self.addSections(Zoom_Loading_Section())

工厂方法模式实现细节:

创建一个名为Map_Profile的抽象类Creator,其提供一个工厂方法createPrfile(),Map_Profile抽象类由self.sections列表存储具体需实例化的对象。具体工厂ConcreteCreator类比如Full_Load(Map_Profile)和Zoom_Loading(Map_Profile)通过继承重写,每个类都实现了createPrfile()抽象方法,由该方法在运行时实际创建(实例化),创建需要的资源加载到相应的对象存储空间即对象池。

2、应用客户端-Map_server_client.py

代码语言:javascript
复制
from apps.tools.Map_Load import ForestFactory

class webservice_client():
    def __init__(self,BaseAlgorithm,data):
        # super(webservice_client, self).__init__()
        # 定义客户端对象
        self.BaseAlgorithm = BaseAlgorithm
        self.data = data

    @fail_data(msg='地图加载失败')
    def get_Map_model(self):
        # f = ForestFactory()
        # Map = f.make_execute(self.BaseAlgorithm,self.data)

        Section = eval(self.BaseAlgorithm)(self.data)
        Card_Section = Section.getSections()[0].execute(self.data)
        Map = Section.getSections()[1].execute(self.data,Card_Section)

        return Map

实现权限管理

随着应用功能拓展,需要更好的管理组织产品功能类时,对以上抽象工厂类代码结构升级改造变体,利用字典注册功能,松耦合,功能通过注册使用,工厂方法模式实现权限管理功能。

代码语言:javascript
复制
#抽象工厂--功能注册
class Profile_registration(metaclass=ABCMeta):
    def __init__(self):
        self.sections = {}
        self.createPrfile()

    @abstractmethod
    def createPrfile(self):
        pass

    def getSections(self):
        return self.sections

    def addSections(self,section):
        self.sections.update({type(section).__name__:section})

class Full_Load_v1(Profile_registration):
    """
   地图一次性全加载
    """
    def __init__(self,data):
        super(Full_Load_v1, self).__init__()
        #公共部分
        self.data = data

    def createPrfile(self):
        self.addSections(Other_Section())
        self.addSections(Card_Section())
        self.addSections(Full_Load_Section())

class Zoom_Loading_v1(Profile_registration):
    """
    地图缩放加载
    """
    def __init__(self,data):
        super(Zoom_Loading_v1, self).__init__()
        #公共部分
        self.data = data

    def createPrfile(self):
        self.addSections(Card_Section())
        self.addSections(Zoom_Loading_Section())

# 客服端代码测试
if __name__ =='__main__':
    Profile_type = input("Which Profile you'd like to create? [Full_Load_v1 or Zoom_Loading_v1]")
    data = pd.read_excel(r".\apps\Mapview\data1.xlsx",index_col=False)
    Section = eval(Profile_type)(data)
    Section_dict =Section.getSections()
    print("Map_Profile has sections --",Section_dict)
    print("Card_Section --", Section_dict.get('Card_Section'))
    print("Other_Section --", Section_dict.get('Other_Section').execute())

#测试结果

代码语言:javascript
复制
Which Profile you'd like to create? [Full_Load_v1 or Zoom_Loading_v1]Full_Load_v1
Map_Profile has sections -- {'Other_Section': <__main__.Other_Section object at 0x000001429616E2B0>, 'Card_Section': <__main__.Card_Section object at 0x00000142992E2D68>, 'Full_Load_Section': <__main__.Full_Load_Section object at 0x00000142992E28D0>}
Card_Section -- <__main__.Card_Section object at 0x00000142992E2D68>
Other Section
Other_Section -- Other Section

运行代码,按要求输入要创建的具体工厂类,以Full_Load_v1为例,实例化创建具体子类Other_Section、Card_Section、Full_Load_Section。获取字典具体对象名使用实例化好的对象。自主决定实例化哪些类或使用哪些对象,对象管理更加灵活。

如果需要向应用中添加一种新产品,你只需要开发新的具体子类产品,然后重写其工厂方法即可,并在具体工厂类中注册取用。

当应用功能越来越复杂时,设计模式开始显得尤为重要,面向接口开发,而不是面向具体实现。许多项目前期初期版本会使用工厂方法模式,其较为简单,方便通过子类进行定制,随着演变为使用抽象工厂,更加灵活复杂。

抽象工厂模式:包含一个或多个工厂方法来创建一个系列的相关对象,使用组合将创建对象的任务委托给其他类。

在抽象工厂模式中,抽象产品 (AbstractProduct) 可能是一个或多个,从而构成一个或多个产品族(Product Family)。在只有一个产品的情况下,抽象工厂模式实际上退化到工厂方法模式。抽象工厂方法无需指定具体的类就能创建一系列相关对象。后期结合合适实例再详细讲解。

以上为本次分享的全部内容,文中已包含大部分源代码,在此基础上,我想可以拓展实现不同的权限显示不同的功能或模块,各位小伙伴赶快动手实践一下吧!原创不易,欢迎点赞、分享支持。

下一篇进一步研究其他类型模式,敬请期待!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-04-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Python数据分析实例 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
对象存储
对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档