zoukankan      html  css  js  c++  java
  • 工厂模式之简单工厂模式

    简单工厂模式简介

    工厂模式有一种非常形象的描述,建立对象的类就如一个工厂,而需要被建立的对象就是一个个产品;在工厂中加工产品,使用产品的人,不用在乎产品是如何生产出来的。从软件开发的角度来说,这样就有效的降低了模块之间的耦合。

    简单工厂的作用是实例化对象,而不需要客户了解这个对象属于哪个具体的子类。简单工厂实例化的类具有相同的接口或者基类,在子类比较固定并不需要扩展时,可以使用简单工厂。如数据库生产工厂就是简单工厂的一个应用

    • 优点:可以使用户根据参数获得对应的类实例,避免了直接实例化类,降低了耦合性;
    • 缺点:可实例化的类型在编译期间已经被确定,如果增加新类 型,则需要修改工厂,不符合OCP(开闭原则)的原则。简单工厂需要知道所有要生成的类型,当子类过多或者子类层次过多时不适合使用。

    面向对象的要点

    • 面向对象三大特性:封装、继承、多态。
    • 通过封装、继承、多态把程序耦合降低。
    • 业务逻辑和界面逻辑分开。

    程序设计的要点

    • 程序应该做到:(1)可维护;(2)可复用;(3)可扩展;(4)灵活性好。
    • 可维护:就是说代码一处更改,不能产生连锁反应,不能影响其他地方。
    • 可复用:尽量减少重复性代码。
    • 可扩展:如果要扩展新的功能、新的业务,则只需要增加新的类就好了,不对已有的类和逻辑产生影响。插拔式的应用

    实例分析

    题目:

    用任意一种面向对象语言实现一个计算器控制台程序。要求输入两个数和运算符号,得到结果。

    设计有缺陷的代码

    #!/usr/bin/env python
    # _*_ coding utf-8 _*_
    #Author: aaron
    
    num1 = int(input('请输入第一个数:'))
    op =input('请输入运算符(+ - * /):')
    num2 = int(input('请输入第一个数:'))
    
    if op == '+':
        res = num1 + num2
    elif op == '-':
        res = num1 - num2
    elif op == '*':
        res = num1 * num2
    elif op == '/':
        res = num1 / num2
    
    print('运算结果为:',res)
    

     存在的问题

    • 业务逻辑和界面逻辑没有分开
    • 业务逻辑有漏洞(除法中num2没有做非零判断)
    • 不具有扩展性(无法添加新功能,eg:加入平方运算,再加入一条“elif语句”是很糟糕的修改方式,下文详细叙述)
    • 可维护性差(eg:加入平方运算时,很可能修改其他地方的源代码,有人就说了,怎么可能,不就是再加入一条“elif语句”吗?是的,反这种低级错误的概率很小,我所说的是恶意修改源代码。当然,又有人反驳了,不就是添加一种运算吗,我修改其他运算干嘛?是的,非常正确。但你想过没,如果我们这里的“if语句”不是做运算符的判断,而是做某个公司的薪资计算呢,那修改代码的程序员会不会恶意将和自己相关的地方修改了呢?这也解释了不具有扩展性的问题了)

    完善后的代码

    设计思路分析

    1. 首先,搞清楚业务中容易发生变化的部分。在本应用中,要求计算两个数的运算结果,那么要进行什么样的运算,这就是一个容易发生变化的部分。例如,我们现在只想实现加减乘除运算,后期又想增加开根或者求余运算。那么如何应对这种需求带来的变化。在程序设计的时候就应该考虑到程序的可维护性、可扩展性、代码的可复用性、灵活性等等。
     
    2. 例如现在这个运算器只有加减乘除四种运算。首先建一个Operation类,这个类是各种具体运算类(加减乘除)的父类,主要是接受用户输入的数值。该类如下:

    class Operation():  
        def __init__(self,NumberA=0,NumberB=0):  
            self.NumberA = NumberA  
            self.NumberB = NumberB  
      
        def GetResult(self):  
            pass  
    

     3. 然后是具体的运算类:Add、Sub、Mul、Div。他们都继承了Operation类,并且重写了getResult()方法。这样就可以用多态性降低不同业务逻辑的耦合度,修改任何一种运算类都不会影响其他的运算类。具体类的代码如下:

    class AddOp(Operation):  
        def GetResult(self):  
            return self.NumberB + self.NumberA  
      
    class MinusOp(Operation):  
        def GetResult(self):  
            return self.NumberA - self.NumberB  
      
    class MultiOp(Operation):  
        def GetResult(self):  
            return self.NumberA * self.NumberB  
      
    class DivideOp(Operation):  
        def GetResult(self):  
            try:  
                return 1.0*self.NumberA / self.NumberB  
            except ZeroDivisionError:  
                raise  
    

     4.  那么如何让计算器知道我是要用哪一种运算呢?也就是说到底要实例化哪一个具体的运算类,Add?Sub?Mul?Div?这时就应该考虑用 一个单独的类来做这个创造具体实例的过程,这个类就是工厂类。如下:

    class OperationFatory():  
        def ChooseOperation(self,op):  
            if op == '+':  
                return AddOp()  
            if op == '-':  
                return MinusOp()  
            if op == '*':  
                return MultiOp()  
            if op == '/':  
                return DivideOp()  
    

     5. 这样,用户只要输入运算符,工厂类就可以创建合适的实例,通过多态性,即返回给父类的方式实现运算结果。客户端代码如下:

    if __name__ == '__main__':  
        ch = ''  
        while not ch=='q':   
            NumberA = eval(raw_input('Please input number1:  '))  
            op = str(raw_input('Please input the operation:  '))  
            NumberB = eval(raw_input('Please input number2:  '))  
            OPFactory = OperationFatory()  
            OPType = OPFactory.ChooseOperation(op)  
            OPType.NumberA = NumberA  
            OPType.NumberB = NumberB  
            print 'The result is:',OPType.GetResult()  
            print '
    #--  input q to exit any key to continue'  
            try:  
                ch = str(raw_input())  
            except:  
                ch = ''  
    

    完整版代码:

    # -*-coding:UTF-8-*-  
    from abc import ABCMeta,abstractmethod
    
    class Operation():
    	def __init__(self,NumberA=0,NumberB=0):
    		self.NumberA = NumberA
    		self.NumberB = NumberB
    
    	def GetResult(self):
    		pass
    
    class AddOp(Operation):
    	def GetResult(self):
    		return self.NumberB + self.NumberA
    
    class MinusOp(Operation):
    	def GetResult(self):
    		return self.NumberA - self.NumberB
    
    class MultiOp(Operation):
    	def GetResult(self):
    		return self.NumberA * self.NumberB
    
    class DivideOp(Operation):
    	def GetResult(self):
    		try:
    			return 1.0*self.NumberA / self.NumberB
    		except ZeroDivisionError:
    			raise
    
    class OperationFatory():
    	def ChooseOperation(self,op):
    		if op == '+':
    			return AddOp()
    		if op == '-':
    			return MinusOp()
    		if op == '*':
    			return MultiOp()
    		if op == '/':
    			return DivideOp()
    
    if __name__ == '__main__':
    	ch = ''
    	while not ch=='q': 
    		NumberA = eval(raw_input('Please input number1:  '))
    		op = str(raw_input('Please input the operation:  '))
    		NumberB = eval(raw_input('Please input number2:  '))
    		OPFactory = OperationFatory()
    		OPType = OPFactory.ChooseOperation(op)
    		OPType.NumberA = NumberA
    		OPType.NumberB = NumberB
    		print 'The result is:',OPType.GetResult()
    		print '
    #--  input q to exit any key to continue'
    		try:
    			ch = str(raw_input())
    		except:
    			ch = ''
    

     

  • 相关阅读:
    剑指offer:二进制中1的个数
    剑指offer:反转链表
    剑指offer:链表中倒数第k个结点
    剑指offer:调整数组顺序使奇数位于偶数前面
    剑指offer:矩形覆盖
    剑指offer:变态跳台阶
    剑指offer :跳台阶
    剑指offer:旋转数组的最小数字
    剑指offer:用两个栈实现队列
    剑指offer:重建二叉树
  • 原文地址:https://www.cnblogs.com/cjaaron/p/9026974.html
Copyright © 2011-2022 走看看