Python面向对象程序设计之抽象工厂模式之二-一个更加pythonic的抽象工厂

上一篇文章我们说到DiagramFactory和其SvgDiagramFactory子类以及它们使用到的类比如(Diagram,SvgDiagram等等),能够很好的实现预订的功能并且也符合抽象工厂的设计模式。

然而,我们的实现并非是非常完美的,至少还有以下几点不足:

1)我们并不需要保存每个工厂的状态,因此,在向create_diagram传递参数的时候,就没有必要传递工厂的实例。

2)SvgDiagramFactory的代码几乎和DiagramFactory完全一样,唯一的区别就在于其返回值在Text或Rectangle的前面加了Svg的前缀,即:SvgText SvgRectangle等等。

3)我们的顶层命名空间中保存了所有的类:DiagramFactory、Digram、Rectangle、TeXT以及所有的SVG相关的类。然而,实际上我们真正需要从外部调用的仅有两个工厂类而已。

4)为了避免类名称的冲突,我们不得不在子类的名称前面添加SVG前缀,实际而言,这样的代码看起来不是很整洁。(解决类名称冲突的另一个解决办法是:把每个类放到自己的模块内部,但是这样做却依然解决不了代码重复的问题)。

本文就着力解决上述四点问题。

我们所要做的第一个改变就是将Diagram,Rectangle及Text类封装进DiagramFactory类中。这就意味着只能用类似于DiagramFactory.Diagram的形式访问这些类。但是,现在我们就就可以为这些类起相同的名字了,因为类名冲突将不复存在,比如SvgDiagramFactory.Diagram。我们也把类所依赖的一些常量封装进了内部,所有,在本模块的内部顶级名称只有:main(), create_diagram(), DiagramFactory和SvgDiagramFactory。

class DiagramFactory: 
@classmethod?
def make_diagram(Class, width, height): 
return Class.Diagram(width, height) 
@classmethod?
def make_rectangle(Class, x, y, width, height, fill="white", 
stroke="black"):?
return Class.Rectangle(x, y, width, height, fill, stroke) 
@classmethod?def make_text(Class, x, y, text, fontsize=12): 
return Class.Text(x, y, text, fontsize) 
...

这是我们的新的DiagramFactory类。其中的make_...()方法全部都是类方法。这也就意味着。当被调用时,类将作为第一个参数传递给该函数(就像self被传递给普通类方法一样)。所以,在这种情况下调用DiagramFactory.make_text()就意味着DiagramFactory作为class参数被传递进去,从而一个DiagramFactory.Text对象被创建并返回。

这个改变也意味着,作为派生自DiagramFactory的SvgDiagramFactory类,不再需要自己实现make_...()的函数。比如说,当我们调用SvgDiagramFactory.make_rectangle()这个方法,由于SvgDiagramFactory里并没有该方法,因此就会调用其基类的DiagramFactoy.make_rectangle()方法,但是传进去的class参数确是SvgDiagramFactory.因此,就导致SvgDiagramFactory.Rectangle对象创建并返回。

def main(): ... 
    txtDiagram = create_diagram(DiagramFactory)
    txtDiagram.save(textFilename)
    svgDiagram = create_diagram(SvgDiagramFactory)
    svgDiagram.save(svgFilename)

这些改变也意味着我们可以简化main()函数的设计,因为我们无需再创建factory工厂的实例了。

其余的代码基本和之前一样。比较明显的区别就在于因为我们将常量和非工厂类都封装进工厂的类代码里,我们现在必须使用工厂名称来访问它们。

class SvgDiagramFactory(DiagramFactory): 
... 
class Text: 
def __init__(self, x, y, text, fontsize): 
x *= SvgDiagramFactory.SVG_SCALE?
y *= SvgDiagramFactory.SVG_SCALE 
fontsize *= SvgDiagramFactory.SVG_SCALE // 10?
self.svg = SvgDiagramFactory.SVG_TEXT.format(**locals())

这是封装进SvgDiagramFactory类的代码里的Text类,演示了封装的常量是如何被访问的。

好了,这就是抽象工厂代码的的进一步优化,后面我们还会涉足其他设计模式,敬请期待!

原文地址:http://blog.51cto.com/13466841/2128773

时间: 2024-10-09 12:17:21

Python面向对象程序设计之抽象工厂模式之二-一个更加pythonic的抽象工厂的相关文章

5.4 SAP ABAP 面向对象概念 - 多态 - 摘自 《SAP ABAP面向对象程序设计:原则、模式及实践》

<SAP ABAP面向对象程序设计:原则.模式及实践> https://book.douban.com/subject/30317853/ http://www.duokan.com/shop/tbt/book/179473 https://item.jd.com/12423999.html https://e.jd.com/30429611.html 5.4 多态 5.4.1 多态的概述 多态是一个生物学和化学中的专有名词,被面计算机科学家引用到面向对象的程序设计中. 我们用柯林斯英语词典看

4.4 类的方法(Methods)- 摘自 《SAP ABAP面向对象程序设计:原则、模式及实践》

<SAP ABAP面向对象程序设计:原则.模式及实践> https://book.douban.com/subject/30317853/ http://www.duokan.com/shop/tbt/book/179473 https://item.jd.com/12423999.html https://e.jd.com/30429611.html 4.4 类的方法(Methods) 类的方法(Methods),指明类具有的功能.数据和服务包成了一个整体,能够有一系列的行为和动作. 类的方

python面向对象程序设计(类成员)第二节

python 面向对象程序设计(类成员) 目录: (1)        类成员和实例成员 (2)        公有成员和私有成员 (3)        方法 (一)类成员与实例成员: 实例属性属于实例(对象),只能通过对象名访问. 类属性属于类,类名或对象名都可以访问,属于类的数据成员是在类中所有方法之外定义的. class Car:     price = 1000   #类属性     def __init__(self,c):         self.color = c car1 =

设计模式:工厂模式(续:虚构造函数和抽象工厂)

在之前的<设计模式:工厂模式>中记录了两种用于创建派生类对象的工厂模式,第一种模式直接使用基类的静态成员函数来创建派生类的对象,在该静态成员函数中直接调用了派生类的构造函数,第二种模式是使用基类工厂的静态成员函数,通过基类工厂中保存的各派生类工厂来创建派生类对象,派生类工厂是派生类的嵌套类,相当于为派生类量身定做的专属工厂,这些专属工厂的存在使得基类工厂不必了解创建派生类对象的细节.今天主要记录另外两种工厂模式:虚构造函数和抽象工厂.虚构造函数模式与前两种工厂模式不同,在前两种工厂模式中,基类

C#面向对象设计之——简单工厂模式(二)

一.前言 简单工厂是一个负责生产对象的中间类,例如有加减乘除四个运算方法,它们继承父类,并重写父类的方法,简单工厂根据不同的运算符创建不同的实例对象赋值给父类,实现了面向对象的另一个原则——降低对象之间的耦合度.简单工厂模式解决了客户端直接依赖于具体对象的问题,客户端可以消除直接创建对象的责任,而仅仅是消费产品.简单工厂模式实现了对责任的分割. 简单工厂模式的缺点: 工厂类集中了所有产品创建逻辑,一旦不能正常工作,整个系统都会受到影响 系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,这样就会造

工厂模式(二)

工厂方法模式:简单工厂模式的进一步抽象和推广.工厂方法模式把简单工厂中的具体的工厂类划分为两层:抽象工厂层+具体工厂层,类图如下: 涉及到的角色: 抽象产品角色:所有产品的共同父类或共有接口,用以实现多态. 1 //电脑接口 2 public interface Icomputer{ 3 } 具体产品角色:实现抽象产品角色所声明的接口. 1 //戴尔电脑 2 public class Dell implements Icomputer{ 3 } 1 //联想电脑 2 public class L

C#面向对象设计之——策略者模式(二十)

一.前言 策略模式定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户. 二.结构图 三.实例代码 using System; using System.Collections.Generic; using System.Text; namespace 策略模式 { class Program { static void Main(string[] args) { Context context; context = new Context(new

设计模式之工厂模式(二)

之前已经带大家稍微入门了工厂模式(即简单工厂模式)的方法,没看过的朋友可以移步去查看一番.设计模式之工厂模式(一).今天我们继续吃着披萨,学习着工厂模式的接下来部分吧. 加盟披萨店 我们先前的披萨店已经经营有成,击败了部分竞争者,接下来的计划就是开加盟店.作为经营者,你肯定希望确保加盟店运营的质量,所以希望这些店都是用你那些经过时间考验的代码. 但是每个地方可能需要不同口味的披萨(比如A地区.B地区.C地区等),这就是开店地点以及该地区披萨美食家口味的影像. 如果利用先前的简单工厂,那么就是需要

Java的工厂模式(二)

除了上文提到的方法之外,还可以使用Java的反射机制,这样就能使用类名称来加载所需要的类.我们只需改变工厂类和驱动类就可以了. FruitFactory.java package com.muggle.project; //水果工厂 public class FruitFactory { public FruitInterface getFruit(String key) { if("Banana".equals(key)) { return new Banana(); } else