预备知识:

开放封闭原则(Open-Closed Principle OCP)

Software entities(classes,modules,functions etc) should open for extension ,but close for modification.

所谓开放封闭原则就是软件实体应该对扩展开放,而对修改封闭。开放封闭原则是所有面向对象原则的核心。

软件设计本身所追求的目标就是封装变化,降低耦合,而开放封闭原则正是对这一目标的最直接体现。

对扩展开放,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况。

对修改封闭,意味着类一旦设计完成,就可以独立其工作,而不要对类尽任何修改。

单一职责原则:(SRP:Single responsibility principle)
 
又称单一功能原则,面向对象五个基本原则(SOLID)之一。它规定一个类应该只有一个发生变化的原因。
所谓职责是指类变化的原因。如果一个类有多于一个的动机被改变,那么这个类就具有多于一个的职责。而单一职责原则就是指一个类或者模块应该有且只有一个改变的原因。

以上,是抄得。

ok, 故事开始。

从去年开始,我们公司搞起了O2O开放平台。提供了O2O各个语言版本的基础库,比如c# php java python等.

随着时间的推移,接入开放平台的企业越来越多,使用各种语言的版本。

那么,我们写代码模拟这个过程。

写之前,介绍一下python的“属性”。

为什么要介绍这个东西,因为我之前是个c#程序猿,用得最多的就是这货。

在绑定属性时,如果我们直接把属性暴露出去,虽然写起来很简单,但是,没办法检查参数,导致可以把成绩随便改:

s = Student()
s.score = 9999

这显然不合逻辑。为了限制score的范围,可以通过一个set_score()方法来设置成绩,再通过一个get_score()来获取成绩,这样,在set_score()方法里,就可以检查参数:

class Student(object):

    def get_score(self):
return self._score def set_score(self, value):
if not isinstance(value, int):
raise ValueError('score must be an integer!')
if value < 0 or value > 100:
raise ValueError('score must between 0 ~ 100!')
self._score = value

现在,对任意的Student实例进行操作,就不能随心所欲地设置score了:

>>> s = Student()
>>> s.set_score(60) # ok!
>>> s.get_score()
60
>>> s.set_score(9999)
Traceback (most recent call last):
...
ValueError: score must between 0 ~ 100!

但是,上面的调用方法又略显复杂,没有直接用属性这么直接简单。

有没有既能检查参数,又可以用类似属性这样简单的方式来访问类的变量呢?对于追求完美的Python程序员来说,这是必须要做到的!

还记得装饰器(decorator)可以给函数动态加上功能吗?对于类的方法,装饰器一样起作用。Python内置的@property装饰器就是负责把一个方法变成属性调用的:

class Student(object):

    @property
def score(self):
return self._score @score.setter
def score(self, value):
if not isinstance(value, int):
raise ValueError('score must be an integer!')
if value < 0 or value > 100:
raise ValueError('score must between 0 ~ 100!')
self._score = value
>>> s = Student()
>>> s.score = 60 # OK,实际转化为s.set_score(60)
>>> s.score # OK,实际转化为s.get_score()
60
>>> s.score = 9999
Traceback (most recent call last):
...
ValueError: score must between 0 ~ 100!
就是这么好用(当然,比起c#来说,还是有点丑陋,为什么我就不说了..毕竟php是世界上最好的语言) ok,现在开始开放平台的接入工作。于是我们写了如下代码:
# -*- coding: utf-8 -*-

class OpenService(object):

    @property
def language(self):
return self.__language @language.setter
def language(self, value):
self.__language = value def __init__(self):
self.__language = 'csharp' def attack_cities(self):
if self.__language == 'python':
print '攻城师 苦逼兮兮, 写python'
elif self.__language == 'java':
print '攻城师 苦逼兮兮, 写java'
elif self.__language == 'php':
print '攻城师 屌屌的, 写php,毕竟php是世界上最好的语言'
elif self.__language == 'c#':
print '攻城师 苦逼兮兮, 写c#' if __name__ == "__main__":
open_service = OpenService()
print '某公司1开始对接python...'
open_service.language = 'python'
open_service.attack_cities() print '某公司2开始对接java...'
open_service.language = 'java'
open_service.attack_cities() print '某公司3开始对接php...'
open_service.language = 'php'
open_service.attack_cities() print '某公司4开始对接c#...'
open_service.language = 'c#'
open_service.attack_cities()
PM一声令下,公司1,2,3,4 纷纷对接开放平台.
过了一段时间,触宝又增加了,c++,c,vb.....等各种语言的开放平台sdk...
那么怎么办呢?很简单..在attack_cities 方法里加更多的if else 判读呗...
于是代码的坏味道出现了....
1. 过长的if else 是明显的坏味道..
2. 写代码是个复杂的过程,全部写在一个方法里...这个方法明显职责过重.违背了本文一开始的单一职责原则。 是时候重构了,当当当当,静态工厂模式善良登场。

简单工厂模式


简单工厂模式是属于创建型模式,又叫做静态工厂方法(Static Factory Method)模式。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式,可以理解为是不同工厂模式的一个特殊实现。
 
该模式中包含的角色及其职责
工厂(Creator)角色
简单工厂模式的核心,它负责实现创建所有实例的内部逻辑。工厂类的创建产品类的方法可以被外界直接调用,创建所需的产品对象。
抽象产品(Product)角色
简单工厂模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口。
具体产品(Concrete Product)角色
是简单工厂模式的创建目标,所有创建的对象都是充当这个角色的某个具体类的实例。


ok,上面也是我抄得。

知道了定义,我们就要对我们的场景做出抽象。变化的部分是语言,以及攻城狮如何攻城。那么我们就需要设计一个语言基类。带有攻城的抽象方法。
然后需要定义一个工厂,根据不同的需求产出不同的语言攻城狮。
当然,为了使用抽象方法,我们必须引入卫生巾模块abc
这样的话,子类如果不实现基类的抽象方法,会抛出not implement 异常(我猜是这个异常) 如下:

import abc
class OpenServiceFactory(object):
languageInstance = None def __init__(self):
pass @staticmethod
def CreateLanguage(language):
if language == 'c#':
OpenServiceFactory.languageInstance = CsharpLanguage()
elif language == 'java':
OpenServiceFactory.languageInstance = JavaLanguage()
elif language == 'php':
OpenServiceFactory.languageInstance = PHPLanguage()
elif language == 'python':
OpenServiceFactory.languageInstance = PythonLanguage() return OpenServiceFactory.languageInstance class LanageBase(object):
@abc.abstractmethod
def att_cities(self):
pass class CsharpLanguage(LanageBase):
def att_cities(self):
print '攻城师 苦逼兮兮, 写c#' class JavaLanguage(LanageBase):
def att_cities(self):
print '攻城师 苦逼兮兮, 写java' class PHPLanguage(LanageBase):
def att_cities(self):
print '攻城师 屌屌的, 写php,毕竟php是世界上最好的语言' class PythonLanguage(LanageBase):
def att_cities(self):
print '攻城师 苦逼兮兮, 写python'

测试:

if __name__ == "__main__":

    print '简单工厂思密达'

    print '某公司1开始对接python...'
open_service = OpenServiceFactory.CreateLanguage('python')
open_service.att_cities() print '某公司2开始对接java...'
open_service = OpenServiceFactory.CreateLanguage('java')
open_service.att_cities() print '某公司3开始对接php...'
open_service = OpenServiceFactory.CreateLanguage('php')
open_service.att_cities() print '某公司4开始对接c#...'
open_service = OpenServiceFactory.CreateLanguage('c#')
open_service.att_cities()

运行:

➜  static_factory python static_factory.py

某公司1开始对接python...

攻城师 苦逼兮兮, 写python

某公司2开始对接java...

攻城师 苦逼兮兮, 写java

某公司3开始对接php...

攻城师 屌屌的, 写php,毕竟php是世界上最好的语言

某公司4开始对接c#...

攻城师 苦逼兮兮, 写c#

简单工厂思密达

某公司1开始对接python...

攻城师 苦逼兮兮, 写python

某公司2开始对接java...

攻城师 苦逼兮兮, 写java

某公司3开始对接php...

攻城师 屌屌的, 写php,毕竟php是世界上最好的语言

某公司4开始对接c#...

攻城师 苦逼兮兮, 写c#

➜  static_factory

结论: 简单工厂模式并没有消除工厂类的条件判断

    当有需求扩展时候,必须修改工厂类,违背了了本文一开始提出的开放封闭原则

所以,这不是一个完美的模式,于是有人把简单工厂开除出了设计模式。

真是的。其实人家也是有不少优点的。

1. 减少耦合,子类单独实现算法

2. 客户端调用时,只需关心工厂类,减少复杂度

3. 工厂封装和抽象了变化的部分,通过工厂来实现了子类的创建,子类通过多态实现基类方法.

以上,简单工厂模式,希望对您有所帮助。。

to be continued

 

[python实现设计模式]-3.简单工厂模式-触宝开放平台的更多相关文章

  1. C#设计模式(2)-简单工厂模式

    引言 上一遍中介绍了设计模式中的单例模式-C#设计模式(1)-单例模式,本篇将介绍简单工厂模式,也是比较容易理解的一种模式: 简单工厂模式简介 什么是简单工厂模式? 定义一个工厂类,它可以根据参数的不 ...

  2. C#设计模式(2)——简单工厂模式(转)

    C#设计模式(2)——简单工厂模式   一.引言 这个系列也是自己对设计模式的一些学习笔记,希望对一些初学设计模式的人有所帮助的,在上一个专题中介绍了单例模式,在这个专题中继续为大家介绍一个比较容易理 ...

  3. Jquery如何序列化form表单数据为JSON对象 C# ADO.NET中设置Like模糊查询的参数 从客户端出现小于等于公式符号引发检测到有潜在危险的Request.Form 值 jquery调用iframe里面的方法 Js根据Ip地址自动判断是哪个城市 【我们一起写框架】MVVM的WPF框架(三)—数据控件 设计模式之简单工厂模式(C#语言描述)

    jquery提供的serialize方法能够实现. $("#searchForm").serialize();但是,观察输出的信息,发现serialize()方法做的是将表单中的数 ...

  4. 设计模式之简单工厂模式(Simple Factory)

    原文地址:http://www.cnblogs.com/BeyondAnyTime/archive/2012/07/06/2579100.html 今天呢,要学习的设计模式是“简单工厂模式”,这是一个 ...

  5. iOS设计模式 - (3)简单工厂模式

    iOS设计模式 - (3)简单工厂模式           by Colin丶 转载请注明出处:              http://blog.csdn.net/hitwhylz/article/ ...

  6. C#设计模式(2)——简单工厂模式

    一.概念:简单工厂模式(Simple Factory Pattern)属于类的创新型模式,又叫静态工厂方法模式(Static FactoryMethod Pattern),是通过专门定义一个类来负责创 ...

  7. python设计模式 之 简单工厂模式

    简单工厂模式属于类的创建型模式,适合用来对大量具有共同接口的类进行实例化,它能够推迟到执行的时候才动态决定要创建哪个类的实例.而不是在编译时就必须知道要实例化哪个类. python: #!/usr/b ...

  8. 《大话设计模式》——简单工厂模式(Python版)

    简单工厂模式(Simple Factory Pattern):是通过专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类. 例: 使用Python设计一个控制台计算器,要求输入两个数 ...

  9. 设计模式之简单工厂模式Simple Factory(四创建型)

    工厂模式简介. 工厂模式专门负责将大量有共同接口的类实例化 工厂模式可以动态决定将哪一个类实例化,不必事先知道每次要实例化哪一个类. 工厂模式有三种形态: 1.简单工厂模式Simple Factory ...

随机推荐

  1. akka实现的actor

    定义一个 Actor 类 要定义自己的Actor类,需要继承 Actor 并实现receive 方法. receive 方法需要定义一系列 case 语句(类型为 PartialFunction[An ...

  2. JUnit3的作用

    简要说JUnit的4大功能 1. 管理测试用例.修改了哪些代码,这些代码的修改会对哪些部分有影响,通过JUnit将这次的修改做个完整测试.这也就JUnit中所谓的TestSuite. 2. 定义测试代 ...

  3. iptables的扩展匹配

    iptables的匹配条件 一.通用匹配:-s.-d.-p.-i.-o 二.扩展匹配 1.隐含扩展:使用-p{tcp|udp|icmp}指定某特定协议后,自动能够对协议进行扩展 -p tcp --dp ...

  4. Java中的抽象类

    含有抽象方法的类,抽象方法即用abstract修饰的方法,即父类只知道其子类应该含有该方法,但无法知道子类如何实现这些方法 抽象类限制规定子类必须实现某些方法,但不关注实现细节 抽象类中可以包含普通方 ...

  5. HDU1434(终于用优先队列a了一题。。。了解度+1)

    #include<iostream> #include<cstdio> #include<cstring> #include<cmath> #inclu ...

  6. 浅谈pads的铜(灌铜)

    在pads中,先按照<pads实战攻略与高速PCB设计>中所说分类,大面积的灌铜有三个重要的概念: (1)copper(铜箔,静态铜): (2)copper pour(覆铜,动态铜): ( ...

  7. 一种让超大banner图片不拉伸、全屏宽、居中显示的方法

    现在很多网站的Banner图片都是全屏宽度的,这样的网站看起来显得很大气.这种Banner一般都是做一张很大的图片,然后在不同分辨率下都是显示图片的中间部分.实现方法如下: <html> ...

  8. oracle数据库从入门到精通之二

    重点关注表的创建与操作语法(如何创建与设计表是后话)常用数据类型表本质上是数据的集合操作数据类型:不管扩展多少种数据类型,常用的就以下几种字符串    varchar2(其它数据库是varchar)来 ...

  9. 在实现和使用上与select和poll有很大差异

    在看此课程的读者,希望先阅读关于函数基础内容 函数定义与函数作用域 的章节,因为此课程或多或少会涉及函数基础的内容,而基础内容,本人放在 函数定义函数作用域 章节. 本文直接赘述函数参数与闭包,若涉及 ...

  10. Web API数据传输加密

    http://www.cnblogs.com/wuhuacong/p/4620300.html Web API应用架构设计分析(2) 在上篇随笔<Web API应用架构设计分析(1)>, ...