python与设计模式之适配器模式和门面模式

python与设计模式之适配器模式

适配器模式定义如下:将一个类的接口变换成客户端期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。

适配器模式和装饰模式有一定的相似性,都起包装的作用,但二者本质上又是不同的,装饰模式的结果,是给一个对象增加了一些额外的职责,而适配器模式,则是将另一个对象进行了“伪装”。
f1.png
适配器可以认为是对现在业务的补偿式应用,所以,尽量不要在设计阶段使用适配器模式,在两个系统需要兼容时可以考虑使用适配器模式。

 

假设某公司A与某公司B需要合作,公司A需要访问公司B的人员信息,但公司A与公司B协议接口不同,该如何处理?先将公司A和公司B针对各自的人员信息访问系统封装了对象接口。

class ACpnStaff(object):
    name=""
    id=""
    phone=""
    def __init__(self,id):
        self.id=id
    def getName(self):
        print("A protocol getName method...id:%s"%self.id)
        return self.name
    def setName(self,name):
        print("A protocol setName method...id:%s"%self.id)
        self.name=name
    def getPhone(self):
        print("A protocol getPhone method...id:%s"%self.id)
        return self.phone
    def setPhone(self,phone):
        print("A protocol setPhone method...id:%s"%self.id)
        self.phone=phone
class BCpnStaff(object):
    name=""
    id=""
    telephone=""
    def __init__(self,id):
        self.id=id
    def get_name(self):
        print("B protocol get_name method...id:%s"%self.id)
        return self.name
    def set_name(self,name):
        print("B protocol set_name method...id:%s"%self.id)
        self.name=name
    def get_telephone(self):
        print("B protocol get_telephone method...id:%s"%self.id)
        return self.telephone
    def set_telephone(self,telephone):
        print("B protocol get_name method...id:%s"%self.id)
        self.telephone=telephone

为在A公司平台复用B公司接口,直接调用B公司人员接口是个办法,但会对现在业务流程造成不确定的风险。为减少耦合,规避风险,我们需要一个帮手,就像是转换电器电压的适配器一样,这个帮手就是协议和接口转换的适配器。适配器构造如下:

class CpnStaffAdapter(object):
    b_cpn=""
    def __init__(self,id):
        self.b_cpn=BCpnStaff(id)
    def getName(self):
        return self.b_cpn.get_name()
    def getPhone(self):
        return self.b_cpn.get_telephone()
    def setName(self,name):
        self.b_cpn.set_name(name)
    def setPhone(self,phone):
        self.b_cpn.set_telephone(phone)

适配器将B公司人员接口封装,而对外接口形式与A公司人员接口一致,达到用A公司人员接口访问B公司人员信息的效果。

if __name__=="__main__":
    acpn_staff=ACpnStaff("123")
    acpn_staff.setName("X-A")
    acpn_staff.setPhone("10012345678")

    print("A Staff Name:%s"%acpn_staff.getName())
    print("A Staff Phone:%s"%acpn_staff.getPhone())

    bcpn_staff=CpnStaffAdapter("456")
    bcpn_staff.setName("Y-B")
    bcpn_staff.setPhone("99987654321")

    print("B Staff Name:%s"%bcpn_staff.getName())
    print("B Staff Phone:%s"%bcpn_staff.getPhone())
打印如下:
A protocol setName method...id:123
A protocol setPhone method...id:123
A protocol getName method...id:123
A Staff Name:X-A
A protocol getPhone method...id:123
A Staff Phone:10012345678
B protocol set_name method...id:456
B protocol get_name method...id:456
B protocol get_name method...id:456
B Staff Name:Y-B
B protocol get_telephone method...id:456
B Staff Phone:99987654321

 

适配器模式的优点:
1、适配器模式可以让两个接口不同,甚至关系不大的两个类一起运行;
2、提高了类的复用度,经过“伪装”的类,可以充当新的角色;
3、适配器可以灵活“拆卸”。
应用场景:
1、不修改现有接口,同时也要使该接口适用或兼容新场景业务中,适合使用适配器模式。例如,在一个嵌入式系统中,原本要将数据从Flash读入,现在需要将数据从磁盘读入,这种情况可以使用适配器模式,将从磁盘读入数据的接口进行“伪装”,以从Flash中读数据的接口形式,从磁盘读入数据。

适配器模式的缺点

1、适配器模式与原配接口相比,毕竟增加了一层调用关系,所以,在设计系统时,不要使用适配器模式。

 

 

python与设计模式之门面模式

门面模式也叫外观模式:要求一个子系统的外部与其内部的通信必须通过一个统一的对象进行。门面模式提供一个高层次的接口,使得子系统更易于使用。门面模式注重“统一的对象”,也就是提供一个访问子系统的接口。

门面模式,是对子系统的封装,其被封装的接口理论上是不会被单独提出来用的。模板模式是对类本身的方法的封装,其被封装的方法也可以单独使用;

f1.png

 

实例

假设有一组火警报警系统,由三个子元件构成:一个警报器,一个喷水器,一个自动拨打电话的装置。其抽象如下:

class AlarmSensor:
    def run(self):
        print("Alarm Ring...")
class WaterSprinker:
    def run(self):
        print("Spray Water...")
class EmergencyDialer:
    def run(self):
        print("Dial 119...")

在业务中如果需要将三个部件启动,例如,如果有一个烟雾传感器,检测到了烟雾。在业务环境中需要做如下操作:

if __name__=="__main__":
    alarm_sensor=AlarmSensor()
    water_sprinker=WaterSprinker()
    emergency_dialer=EmergencyDialer()
    alarm_sensor.run()
    water_sprinker.run()
    emergency_dialer.run()

但如果在多个业务场景中需要启动三个部件,怎么办?Ctrl+C加上Ctrl+V么?当然可以这样,但作为码农的基本修养之一,减少重复代码是应该会被很轻易想到的方法。这样,需要将其进行封装,在设计模式中,被封装成的新对象,叫做门面。门面构建如下:

class EmergencyFacade:
    def __init__(self):
        self.alarm_sensor=AlarmSensor()
        self.water_sprinker=WaterSprinker()
        self.emergency_dialer=EmergencyDialer()
    def runAll(self):
        self.alarm_sensor.run()
        self.water_sprinker.run()
        self.emergency_dialer.run()

 这样,业务场景中这样写就可以了:

if __name__=="__main__":
    emergency_facade=EmergencyFacade()
    emergency_facade.runAll()

打印如下:
Alarm Ring...
Spray Water...
Dial 119...

门面模式的优点:
1、减少了系统之间的相互依赖,提高了系统的灵活;
2、提高了整体系统的安全性:封装起的系统对外的接口才可以用,隐藏了很多内部接口细节,若方法不允许使用,则在门面中可以进行灵活控制。


使用场景:
1、为一个复杂的子系统提供一个外界访问的接口。这类例子是生活还是蛮常见的,例如电视遥控器的抽象模型,电信运营商的用户交互设备等;
2、需要简化操作界面时。例如常见的扁平化系统操作界面等,在生活中和工业中都很常见。

 

门面模式的缺点

1、门面模式的缺点在于,不符合开闭原则,一旦系统成形后需要修改,几乎只能重写门面代码,这比继承或者覆写等方式,或者其它一些符合开闭原则的模式风险都会大一些。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

薛定谔的猫96

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值