第5章:接口实现和多态

Posted lijunjie9502

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第5章:接口实现和多态相关的知识,希望对你有一定的参考价值。

    • 接口
      • 接口是软件资源用户可用的一组操作
      • 接口中的内容是函数头和方法头,以及它们的文档
      • 设计良好的软件系统会将接口与其实现分隔开来
    • 多态
      • 多态是在两个或多个类的实现中使用相同的运算符号、函数名或方法。多态函数的示例是 str len 多态运算符是 + == 多态方法的示例是 add isEmpty
    • 将接口与实现隔开的好处
      • 降低了用户的学习难度
      • 允许用户以即插即用的方式,快速的将资源整合起来
      • 让用户有机会在相同资源的不同实现中做出选择
      • 允许用户对资源的实现做出修改,而不影响用户代码
    • 开发接口
      • 包的接口
        • 包是一种无序的集合
      • 定义包接口
        • 在选择方法名和函数名的时候,应该尽量遵从通用、习惯的用法
        • 包接口中的函数名、方法名和运算符如下:
          • isEmpty
          • len
          • str
          • for
          • in
          • +
          • ==
          • clear
          • add
          • remove
      • 指定参数和返回值
        • 对包接口进行优化,是为接口中的操作添加参数,并用考虑它们返回什么值( 如果有返回值的话 )
        • 迭代器依赖于 iter 方法
        • 包操作及其方法

    用户的包操作

    Bag类中的方法

    b = <class name>( optional collection> )

    __init__( self, sourceCollection = none

    b.isEmpty()

    isEmpty( self )

    len(b)

    __len__( self )

    str( b )

    __str__( self )

    item in b

    __contains___( self, item ): 如果包含了__iter__,就不需要该方法

    b1 + b2

    __add__( self, other )

    b == anyObject

    __eq__( self, other )

    b.clear()

    clear( self )

    b.add( item )

    add( self, item )

    b.remove( item )

    remove( self, item )

    • 构造方法和实现类
      • 数组包
      • 链表包
    • 先验条件、后验条件、异常和文档
      • 文档字符串
        • 3个引号括起来的字符串
        • 当运行 help 函数时,python 会显示这3个字符串
      • 一个方法,如查没有什么可能的错误条件的话,文档字符串只用说明方法的参数是什么、返回值是什么、以及方法执行了什么样的操作
      • 更加详细的文档形式
        • 先验条件 ( Precondition )
          • 是一条语句,只有该语句为真的时候,方法才能正常运行
        • 后验条件( Postcondition )
          • 当方法执行完毕后,什么条件会为真
        • 异常
          • 说明可能发生的异常,通常是无法满足方法的先验条件所致
        • 示例
          • def remove( self, item ):

                """

                Preconditon: item is in self.

                Raise: KeyError if item is not in self.

                Postcondition: item is removed from self.

                """ 

    • Python 编写接口
      • 一些语言,如 Java 提供了编写接口的方法。Python 没有这样的方法,但是可以通过提供文档并指导类的开发,从而模拟类似的功能
      • 为了创建接口,使用文档来列出每一个方法头,并且用一条单个的 pass return 语句来结束每一个方法
      • 示例
        • #!/usr/bin/env python

          # -*- coding:utf-8 -*-

          # Author:Lijunjie

           

          """

          File: baginterface.py

          Author: Lijunjie

          """

           

          class BagInterface( object ):

              """Interface for all bag types."""

             

              #Constructor

              def __init__( self, sourceCollection = None ):

                  """Sets the initial state of self, which includes the contents

                  of sourceCollection, if it‘s present."""

                  pass

                 

                 

              #Accessor methods

              def isEmpty( self ):

                  """Return True if len( self ) == 0, or False otherwise."""

                  return True

                 

                 

              def __len__( self ):

                  """Returns the number of items in self."""

                  return 0

                 

                 

              def __str__( self ):

                  """Return the string representation of self."""

                  return ""

                 

                 

              def __iter__( self ):

                  """Supports iteration over a view of self."""

                  return None

                 

                 

              def __add__( self, other ):

                  """Return a new bag containing the contents of self and other"""

                  return None

                 

                 

              def __eq__( self, other ):

                  """Return True if self equals other, otherwise False."""

                  return False

                 

                 

              #Mutator methods

              def clear( self ):

                  """Makes self become empty."""

                  pass

                 

                 

              def add( self, item ):

                  """Adds item to self."""

                  pass

                 

                 

              def remove( self, item ):

                  """

                  Precondition: item is in self.

                  Raise: KeyError if item is not in self.

                  Postcondition: item is removed form self.

                  """

                  pass

     

    • 开发一个基于数组的实现
      • 集合类的设计确定接口后,类自身的设计和实现包含两个步骤
        • 选择一个合适的数据结构来包含集合的项,并且确定可能需要表示集合状态的任何其他数据。将这些数据赋值给__init__方法中的实例变量
        • 完成接口中相关方法的代码
      • 选择并初始化数据结构
        • #!/usr/bin/env python

          # -*- coding:utf-8 -*-

          # Author:Lijunjie

           

          """

          File: arraybag.py

          Author: Lijunjie

          """

           

          from arrays import Array

           

          class ArrayBag( object ):

              """An array-based bag implementation."""

             

              #Class variable

              DEFAULT_CAPACTIY = 10

             

              #Constructor

              def __init__( self, sourceCollection = None ):

                  """Sets the initial state of self, which includes the contents

                  of sourceCollection, if it‘s present."""

                  self._items = Array( ArrayBag.DEFAULT_CAPACTIY )

                  self._size = 0

                  if sourceCollection:

                      for item in sourceCollection:

                          self.add( item ) 

      • 先完成容易完成的方法
        • 应该尽可能的在 self 上调用方法或函数,而不是直接使用实例变量
        • 代码示例
          •     #Accessor methods

                def isEmpty( self ):

                    """Return True if len( self ) == 0, or False otherwise."""

                    return len( self ) == 0

                   

                   

                def __len__( self ):

                    """Returns the number of items in self."""

                    return self._size

                   

             

                #Mutator methods

                def clear( self ):

                    """Makes self become empty."""

                    self_size = 0

                    self._items = Array( ArrayBag.DEFAULT_CAPACTIY )

                   

                   

                def add( self, item ):

                    """Adds item to self."""

                    #Check array memory here and increase it if necessary.

                    self._items[len( self )] = item

                    self._size += 1

      • 完成迭代器
        • __str____add____eq__等方法,都需要借助 __iter__方法来正确运行
        • __iter__通过 yield 语句,将每一项都发送给 for  循环调用
          •     def __iter__( self ):

                """Supports iteration over a view of self."""

                cursor = 0

                while cursor < len( self ):

                    yield self._items[cursor]

                    cursor += 1

      • 完成使用迭代器的方法
        • __str__函数
          •     def __str__( self ):

                    """Return the string representation of self."""

                    return "{" + ", ".join( map( str, self ) ) + "}" 

        • __add__函数
          •     def __add__( self, other ):

                    """Return a new bag containing the contents of self and other"""

                    result = ArrayBag( self )

                    for item in other:

                        result.add( item )

                    return result

        • __eq__函数
          •     def __eq__( self, other ):

                    """Return True if self equals other, otherwise False."""

                    if self is other: return True

                    if type( self ) != type( other ) or len( self ) != len( other ):

                        return False

                    for item in self:

                        if not item in other:

                            return False

                    return True 

      • in 运算符和 __contains__ 方法
        • in 运算符对应 __contains__ 方法
        • 当类中不包含这个方法时,这个方法会在 self 上使用 for 循环,并进行一次顺序搜索
      • 完成 remove 方法
        •     def remove( self, item ):

                  """

                  Precondition: item is in self.

                  Raise: KeyError if item is not in self.

                  Postcondition: item is removed form self.

                  """

                  if not item in self:

                      raise KeyError( str(item) + " not in bag." )

                  #Search for index of target item.

                  targetIndex = 0

                  for targetItem in self:

                      if targetItem == item:

                          break

                      targetIndex += 1

                 

                  #Shift items

                  for i in range( targetIndex, len( self ) - 1 ):

                      self._items[i] = self._items[i + 1]

                  #Decrement logical size

                  self._size -= 1

                  #Check array memory here and decrease it if necessary 

     

    • 开发一个基于链表的实现
      • 之前开发的 ArrayBag 类中的 __isEmpyt____len____add____eq____str__并没有直接访问数组变量,因此在 LinkedBag 类中,可以不进行修改。
      • 初始化数据结构
        • """

          File: linkedbag.py

          Author: Lijunjie

          """

           

          from node import Node

           

          class LinkedBag( object ):

              """An link-based bag implementation."""

             

              #Constructor

              def __init__( self, sourceCollection = None ):

                  """Sets the initial state of self, which includes the contents

                  of sourceCollection, if it‘s present."""

                  self._items = None

                  self._size = 0

                  if sourceCollection:

                      for item in sourceCollection:

                          self.add( item )

      • 完成迭代器
        •     def __iter__( self ):

                  """Supports iteration over a view of self."""

                  cursor = self._items

                  while not cursor is None:

                      yield cursor.data

                      cursor = cursor.next

      • 完成 clear add 方法
        • clear方法
          •     def clear( self ):

                    """Makes self become empty."""

                    self._size = 0

                    self._items = None

        • add 方法
          •     def add( self, item ):

                    """Adds item to self."""

                    self._items = Node( item, self._items )

                    self._size += 1

      • 完成 remove 方法
        •     def remove( self, item ):

                  """

                  Precondition: item is in self.

                  Raise: KeyError if item is not in self.

                  Postcondition: item is removed form self.

                  """

                  if not item in self:

                      raise KeyError( str(item) + " not in bag." )

                  #Search for the node containing target item.

                  #probe will point to the target node, and trailer will point to

                  #the one before it, if it exists.

                  probe = self._items

                  trailer = None     

                  for targetItem in self:

                      if targetItem == item:

                          break

                      trailer = probe

                      probe = probe.next

                  # Unhook the node to be deleted, either the first one or the

                  #one thereafter

                  if probe == self._items:

                      self._items = self._items.next

                  else:

                      trailer.next = probe.next

                  #Decrement logical size

                  self._size -= 1

    • 两个包实现的运行时性能
      • in remove 操作由于加入了顺序搜索,因此都是线性时间
      • == 操作符默认的时间复杂度为 技术分享图片
      • 剩下的操作都是常数时间,除了 ArrayBag 需要调整数组长度的情况
      • ArrayBag 数组的装填因子超过 0.5 时,其内存占用要比相同逻辑大小的 LinkedBag 要小
    • 测试两个包的实现
      • 测试代码
        • ##!/usr/bin/env python

          # -*- coding:utf-8 -*-

          # Author:Lijunjie

           

          """

          FIle: testbag.py

          Author: Lijunjie

          A test program for bag implementations.

          """

           

          from arraybag import ArrayBag

          from linkedbag import LinkedBag

           

          def test( bagType ):

              """Expects a bag type as argument and runs  some tests on objects

              of that type. """

             

              lyst = [2018, 23, 1995]

              print( "The list of items added is:", lyst )

              b1 = bagType( lyst )

              print( "Expect 3:", len( b1 ) )

              print( "Expect the bag‘s string:", b1 )

              print( "Expect True:", 2018 in b1 )

              print( "Expect False:", 2013 in b1 )

              print( "Expect the items on spearate lines:" )

              for item in b1:

                  print( item )

              b1.clear()

              print( "Expect {}:", b1 )

              b1.add( 25 )

              b1.remove( 25 )

              print( "Expect {}:", b1 )

              b1 = bagType( lyst )

              b2 = bagType( b1 )

              print( "Expect True:", b1 == b2 )

              print( "Expect False:", b1 is b2 )

              print( "Expect two of each items:", b1 + b2 )

              for item in lyst:

                  b1.remove( item )

              print( "Expect crash with keyError:" )

              b2.remove( 99 )

           

          if __name__ == "__main__":

              #test( ArrayBag )

              test( LinkedBag) 

     

    • UML 图表示包资源
      • 统一建模语言( Unified Modeling Language UML  )
        • 带有一个接口和两个实现类的一个类图
          • 技术分享图片
        • 聚合和组合关系
          • 每个 LinkedBag 对象都聚合 0 个或多个节点
          • 每个 ArrayBag 对象都是单个 Array 对象的组合
          • 组合是整体 部分关系,而聚合是一对多的关系
          • 示意图
            • 技术分享图片

以上是关于第5章:接口实现和多态的主要内容,如果未能解决你的问题,请参考以下文章

第8章 多态

java学习--基础知识进阶第三天--接口多态

20165212任胤第四周学习总结

Java面向对象(接口多态)

java编程思想第八章多态

转行小白成长路-java篇

(c)2006-2024 SYSTEM All Rights Reserved IT常识