五 OOP使用工厂函数调用__init__()

工厂函数对__init__()方法的调用

  此文接上一篇文章:https://www.cnblogs.com/liveforlearn/p/15212618.html

    从上两篇文章可以知道,可以通过对AceCard,FaceCard,NumberCard创建card对象,可以枚举出一副牌(52张)

  相比于枚举方法,使用工厂函数来完成Card对象的创建,将是一种更好的选择:

      • 定义一个函数返回不通的对象
      • 定义一个类,包含创建对象的方法

    这是完整的工厂设计模式。在Java语言中,工厂类层次结构是必需的,因为语言本身不支持可以脱离类而单独存在的函数。

                                                         在Python中类的定义是非必需的,仅当特别复杂的情况是,工厂类才是不错的选择。对于只需要简单的定义一个函数就能做到的事情没必要去定义类层次结构,这也是Python的优势之一。

 

Card子类对象在工厂函数中

  “使用工厂函数创建一副牌的实现”

  

 1 # -*- ecoding: utf-8 -*-
 2 # @ModuleName: factory_function
 3 # @Function: 
 4 # @Author: 甲壳虫~~~
 5 # @Time: 2021/8/31 22:53
 6 #@blog:https://www.cnblogs.com/liveforlearn
 7 
 8 from lott_object_book.chapter1.samplest_demo import AceCard, NumberCard, \
 9     FaceCard
10 from lott_object_book.chapter1.constant_list import Club, Diamond, Heart, Spade
11 
12 def card(rank, suit):
13     if rank == 1:
14         return AceCard('A', suit)
15     elif 2 <= rank < 11:
16         return NumberCard(str(rank), suit)
17     elif 11 <= rank < 14:
18         name = {11: 'J', 12: 'Q', 13: 'K'}[rank]
19         return FaceCard(name, suit)
20     else:
21         raise Exception("Rank out of range")
22 
23 deck1 = [card(rank, suit)
24          for rank in range(1, 14) 
25             for suit in (Club, Diamond, Heart, Spade)]

 

小结: 这个函数可以传入牌面值rank,花色suit来使创建对象的工作更加简单。

    这样把创建对象的过程封装在了单独的工厂函数内,外界无需了解对象的层次结构以及多态的工作细节就可以调用工厂函数来创建对象。

      card()函数里的语句并没有使用catch-all else语句做一些其他步骤,只是单纯的抛出了异常

输出内容部分截图:

五 OOP使用工厂函数调用__init__()

 

 

错误示例

  作为高级Python的程序员,不应该把else语句的意图留给读者去推断,条件语句的意图应该是非常直接了当的。

   

 1 # -*- ecoding: utf-8 -*-
 2 # @ModuleName: ambulous_demo
 3 # @Function: 
 4 # @Author: 甲壳虫~~~
 5 # @Time: 2021/9/1 5:53
 6 #@blog:https://www.cnblogs.com/liveforlearn
 7 
 8 from lott_object_book.chapter1.samplest_demo import AceCard, NumberCard, \
 9     FaceCard
10 from lott_object_book.chapter1.constant_list import Club, Diamond, Heart, Spade
11 
12 def card2(rank, suit):
13     if rank == 1:
14         return AceCard('1', suit)
15     elif 1 < rank < 11:
16         return NumberCard(str(rank), suit)
17     else:
18         name = {11: 'J', 12: 'Q', 13: 'K'}[rank]
19         return FaceCard(name, suit)
20 
21 #创建纸牌对象
22 deck2 = [card2(rank, suit)
23          for rank in range(14)
24             for suit in (Club, Diamond, Heart, Spade)]

 

  

  像这样的catch- all else语句是非常有争议的:

    一方面,else不能不做任何事情,因为这样隐藏着微小的设计错误。

    另一方面,一些else语句的意图已经非常明显了。

  因此要避免模糊的else语句

小结:

  什么时候使用catch-all语句

  很少,仅当条件非常明确才使用,如果条件不够明确,使用else语句将抛出异常。因此要避免使用模糊的else语句。

 

使用elif简化设计获得一致性

  工厂方法card()包含两个常见的结构

  • if - elif 序列
  • 映射  

  为了简化重构将是更好的选择

  我们总是可以使用elif条件语句代替映射。(是的,总是可以。但是反过来却不行;把elif转为映射有时是有风险的)

  一下是没有使用映射Card类工厂类的实现。

 

# -*- ecoding: utf-8 -*-
# @ModuleName: simply_factory
# @Function: 
# @Author: 甲壳虫~~~
# @Time: 2021/9/1 6:17
#@blog:https://www.cnblogs.com/liveforlearn

# -*- ecoding: utf-8 -*-
# @ModuleName: ambulous_demo
# @Function: 
# @Author: 甲壳虫~~~
# @Time: 2021/9/1 5:53
#@blog:https://www.cnblogs.com/liveforlearn

from lott_object_book.chapter1.samplest_demo import AceCard, NumberCard, \
    FaceCard
from lott_object_book.chapter1.constant_list import Club, Diamond, Heart, Spade

def card3(rank, suit):
    if rank == 1:
        return AceCard('A', suit)
    elif 1 < rank < 11:
        return NumberCard(str(rank), suit)
    elif rank == 11:
        return FaceCard('J', suit)
    elif rank == 12:
        return FaceCard('Q', suit)
    elif rank == 13:
        return FaceCard('K', suit)
    else:
        raise Exception("Rank out of range")
    

 

  这里重写了card()工厂方法,将映射转为了elif语句。

  比起上一个版本,这个函数在实现上获得了更好的一致性。

 

上一篇:Page Rank 算法


下一篇:oracle的窗口函数