软件设计模式是一个经过多次尝试及测试的解决方案,他可以帮助我们解决代码中经常遇到的问题。有时候你的解决方案中问题一次次的出现,如果遵循某种模式,发现问题就会解决。

即将了解的几种模式为:策略设计模式、简单工厂模式、抽象工厂模式、适配器模式。

首先看几个常用的术语说明:

 先来看几个例子,演示了一种函数名让其他字符代替的方法:

>>> def test():    #定义一个函数
    print("a function")

    
>>> x=test     #函数名给别名x
>>> x()          #别名x可以被调用
a function
>>> x       
<function test at 0x000002446CB15AF0>

另一个例子:

>>> def test1():    #定义一个函数
    print("hahah")

    
>>> def some_function(y):  #定义另一个函数,参数为一个函数名
    y()

    
>>> some_function(test1)   #调用test1函数
hahah
>>> 

类似的,python类也可以作为参数传递。例如:

>>> class Foo:      #定义一个类
    def say_hi(self):
        print("hi")

        
>>> bar=Foo       #类名给别名
>>> z=bar()        #用别名生成实例
>>> z.say_hi()        #实例调用方法
hi

总结:在python中,任何函数、类、类方法或对象,可以自由地执行各种操作,就像在其他实体上的操作一样。

 

继续看例子:

 

def initial_number(x):
    print("1.初始化数字(函数创建时的原始环境):{}".format(x))

    def modified_number(y):
        print("x:{},y:{},x+y:{}".format(x, y, x + y))
        return x + y

    return modified_number


if __name__ == '__main__':
    foo = initial_number(100)
    print("2.现在调用这个函数,并加载其原始环境:")
    foo(1)
    foo(5)

红色函数,内嵌到黄色函数中。当蓝色代码执行后,foo就变成了红色嵌套函数modified_number,同时嵌套函数仍然拥有原来的工作环境,即x=100

输出结果是:

1.初始化数字(函数创建时的原始环境):100
2.现在调用这个函数,并加载其原始环境:
x:100,y:1,x+y:101
x:100,y:5,x+y:105

可以看到x并未变化。任何后续对foo的调用,都保持了原始的本地环境(x=100),该环境由modified_number使用。这就是python中的闭包

 

什么叫类方法?类方法不同于常规的实例方法,类方法不需要创建这个类的实例,就可以对它进行调用。它以类作为它的第一个参数。常用修饰符@classmethod来创建。

什么叫抽象方法?修饰符@abstractmethod修饰的方法表明该方法是抽象的,必须在子类中进行重写

__getattr__方法是什么?当你访问一个类中未定义的实例属性时,python会自动调用__getattr__方法。你可以在类中实现__getattr__。

 

试想一个场景,制作了一个游戏,里面有若干角色:骑士、兽人骑士、精灵骑士、矮人、美人鱼等。这些角色共同继承自一个父类Unit,各自有各自的攻击方法、说明信息。你可以通过在子类中重写方法的模式

来实现功能。但如果有一个”跳“的功能,骑士们都可以跳,而矮人美人鱼无法跳跃,这个该如何实现?

你可以把”跳“这个方法,放到父类中,然后在矮人、美人鱼子类中重写方法(如不做任何事就是不能跳跃),但如果不能跳的角色越来越多,你今后就会不断的重写跳的方法,且重写的很多还是重复的工作。

此时的思路,就应该把”跳“这个行为策略,从父抽象类中拉出,单独建立新的”跳“类。

代码如下:

import sys
from abc import ABCMeta, abstractmethod

if sys.version_info < (3, 0):
    print("This code requires Python 3.x, It is tested only with 3.5 ")
    print("Looks like you are trying to run this using "
          "Python version: %d.%d " % (sys.version_info[0], sys.version_info[1]))
    print("Exiting...")
    sys.exit(1)


class AbstractGameUnit(metaclass=ABCMeta):
    """Base class for all the game characters.

    :arg string name: Name of the game character.
    :arg JumpStrategy jump_object: Could be an instance of JumpStrategy or
                                 its subclasses.(or None if unspecified)
    :ivar jump_strategy: Choose the algorithm for jumping.
    """
    def __init__(self, name, jump_object=None):
        self.jump_strategy = None
        self.name = name
        self.set_jump_strategy(jump_object)

    def set_jump_strategy(self, jump_object=None):
        """Set up the object that defines the jump strategy.

        Choose an algorithm that defines the jump behavior. The algorithm is
        represented by a 'strategy object'.

        :arg JumpStrategy jump_object: Instance of the class that should handle
                    how this game unit 'jumps' . Could be instance of
                    JumpStrategy or its subclasses (or None if unspecified)
        """
        if isinstance(jump_object, JumpStrategy):
            self.jump_strategy = jump_object
        else:
            self.jump_strategy = JumpStrategy()

        # print("\tset_jump_strategy: self.jump_strategy:",
        #       type(self.jump_strategy).__name__)

    def jump(self):
        """Perform jump operation (delegated)"""
        try:
            self.jump_strategy.jump()
        except AttributeError as e:
            print("Error: AbstractGameUnit.jump: self.jump_strategy: {} "
                  "\nError details: {} ".format(self.jump_strategy, e.args))

    @abstractmethod
    def info(self):
        """"Print information about this game unit."""
        pass


class DwarfFighter(AbstractGameUnit):
    """Create a DwarfFighter instance"""
    def info(self):
        """Print info about thus unit, overrides superclass method."""
        print("I am a great dwarf of the eastern foo mountain!")


class JumpStrategy:
    """Base Class representing a jump strategy (an algorithm)."""
    def jump(self):
        """The actual jump algorithm.

         .. seealso: AbstractGameUnit.jump() where this is called
                  (if this jump strategy is chosen)
        """
        print("--> JumpStrategy.jump: Default jump")


class CanNotJump(JumpStrategy):
    """Class whose instance represents a jump algorithm."""
    def jump(self):
        """The actual jump algorithm.

         .. seealso: AbstractGameUnit.jump() where this is called
                  (if this jump strategy is chosen)
        """
        print("--> CanNotJump.jump: I can not jump")


class HorseJump(JumpStrategy):
    """Class whose instance represents a jump algorithm."""
    def jump(self):
        """The actual jump algorithm.

         .. seealso: AbstractGameUnit.jump() where this is called
                  (if this jump strategy is chosen)
        """
        print("--> HorseJump.jump: Jumping my horse.")


class PowerJump(JumpStrategy):
    """Class whose instance represents a jump algorithm."""
    def jump(self):
        """The actual jump algorithm.

         .. seealso: AbstractGameUnit.jump() where this is called
                  (if this jump strategy is chosen)
        """
        print("--> PowerJump.jump: I can jump 100 feet from the ground!")


if __name__ == '__main__':
    # Create a jump strategy instance (algorithm representing a jump behavior)
    jump_strategy = CanNotJump()
    # Pass it to the DwarfFighter.
    dwarf = DwarfFighter("Dwarf", jump_strategy)
    print("\n{STRATEGY-I} Dwarf trying to jump:")
    # The dwarf instance will use the jump strategy represented by CanNotJump()
    dwarf.jump()
    print("-"*56)

    # Optionally change the jump strategy later
    print("\n{STRATEGY-II} Dwarf given a 'magic potion' to jump:")
    dwarf.set_jump_strategy(PowerJump())
    dwarf.jump()
    print("-"*56)
View Code

结果如下:

{STRATEGY-I} Dwarf trying to jump:
--> CanNotJump.jump: I can not jump
--------------------------------------------------------

{STRATEGY-II} Dwarf given a 'magic potion' to jump:
--> PowerJump.jump: I can jump 100 feet from the ground!
--------------------------------------------------------

开始时,矮人跳跃策略是无法跳跃的;将矮人跳跃策略设置为魔法跳,矮人于是有了跳跃技能。

这是传统的策略模式。通常在C++中实现。

 

鉴于python语言的灵活性,python有自己的解决方式(理解为运用函数别名):

import sys
from abc import ABCMeta, abstractmethod

if sys.version_info < (3, 0):
    print("This code requires Python 3.x, It is tested only with 3.5 ")
    print("Looks like you are trying to run this using "
          "Python version: %d.%d " % (sys.version_info[0], sys.version_info[1]))
    print("Exiting...")
    sys.exit(1)

# Callable class moved to collections.callable starting from version 3.3
if sys.version_info < (3, 3):
    from collections import Callable
else:
    from collections.abc import Callable


class AbstractGameUnit(metaclass=ABCMeta):
    """Base class for all the game characters.

    :arg string name: Name of the game character.
    :arg jump_strategy: A callable (function) that represents an algorithm
                     to jump.
    :ivar jump: The jump_strategy function is assigned to this variable.

    .. note: This is created as an abstract class and requires subclasses to
    override the 'info' method. However, you can change this to a simple class
    (not abstract) if you don't want to enforce any interface on the subclasses.
    .. seealso: DwarfFighter (a subclass)
    """
    def __init__(self, name, jump_strategy):
        assert(isinstance(jump_strategy,  Callable))
        self.name = name
        self.jump = jump_strategy

    @abstractmethod
    def info(self):
        """"Print information about this game unit."""
        pass


class DwarfFighter(AbstractGameUnit):
    """Create a DwarfFighter instance"""
    def info(self):
        """Print info about thus unit, overrides superclass method."""
        print("I am a great dwarf of the eastern foo mountain!")


def can_not_jump():
    """A demo function representing a jump algorithm

    .. note:: No actual algorithm is implemented, It prints some information.
    """
    print("--> CanNotJump.jump: I can not jump")


def power_jump():
    """A demo function representing a jump algorithm

    .. note:: No actual algorithm is implemented, It prints some information.
    """
    print("--> PowerJump.jump: I can jump 100 feet from the ground!")


def horse_jump():
    """A demo function representing a jump algorithm

    .. note:: No actual algorithm is implemented, It prints some information.
    """
    print("--> HorseJump.jump: Jumping my horse.")

if __name__ == '__main__':
    # Pass the jump strategy (function) while instantiating the class.
    dwarf = DwarfFighter("Dwarf", can_not_jump)
    print("\n{STRATEGY-I} Dwarf trying to jump:")
    dwarf.jump()
    print("-"*56)

    # Optionally change the jump strategy later
    print("\n{STRATEGY-II} Dwarf given a 'magic potion' to jump:")
    dwarf.jump = power_jump
    dwarf.jump()
    print("-"*56)

实例化dwarf时,传的参数(黄色)为函数名,按红色代码实例化,绿色能调用此函数。蓝色修改了跳跃方式的函数名(调用了对应的其他函数)。

 

简单工厂模式:当一个类中,有个函数能生成多种单位,且这些单位后期能被调用时,可以把这些代码独立出来组成一个类,像“工厂”一样其他代码都可以调用来生产单位。如下代码:黄色工厂从红色

代码中独立出来。

class ElfRider:
    pass
class Knight:
    pass
class OrcRider:
    pass
class DwarfFighter:
    pass
class OrcRider:
    pass
class Fairy:
    pass
class Wizard:
    pass
class ElfLord:
    pass
class OrcFighter:
    pass


class UnitFactory:
    """A simple factory to create and return instances of game units

    .. seealso:: `Kingdom` class and various classes like `ElfRider`, `Knight`
    """
    def create_unit(self, unit_type):
        """The work horse method to create and return instances of a game unit.

        :arg string unit_type: The type of unit requested by the client.
        :return: An instance of a game unit such as ElfRider, Knight, Dwarf etc

        .. todo:: Make this method more robust. e.g. change the string to all
            lower case, add exception handling.
        """
        unit = None

        if unit_type == 'ElfRider':
            unit = ElfRider()
        elif unit_type == 'Knight':
            unit = Knight()
        elif unit_type == "DwarfFighter":
            unit = DwarfFighter()
        elif unit_type == 'OrcRider':
            unit = OrcRider()
        elif unit_type == 'Fairy':
            unit = Fairy()
        elif unit_type == 'Wizard':
            unit = Wizard()
        elif unit_type == 'ElfLord':
            unit = ElfLord()
        elif unit_type == 'OrcFighter':
            unit = OrcFighter()

        return unit


class Kingdom:
    """Class that uses a 'factory' to get an instance of a game character.

    :arg UnitFactory factory: A factory instance used to create new units.
    :ivar UnitFactory factory: Represents a factory instance used to create new
          game units.

    .. seealso:: class `UnitFactory`
    """
    def __init__(self, factory):
        self.factory = factory

    def recruit(self, unit_type):
        """Recruit a new game unit, creating it first using a factory.

        This method recruits a new unit for the 'kingdom'. First it 'orders' a
        unit from the factory instance, then pays the price and updates some
        record. The pay_gold and update_record methods are dummy, they just
        print some information.

        :arg string unit_type:  The type (name) of unit requested.
        :return: A game unit instance returned by the factory.
        """
        unit = self.factory.create_unit(unit_type)
        self.pay_gold(unit)
        self.update_records(unit)
        return unit

    def pay_gold(self, something):
        """Pay gold for the recruited unit (dummy method)."""
        print("GOLD PAID")

    def update_records(self, something):
        """Update some record to reflect new recruit(dummy method)."""
        print("Some logic (not shown) to update database of units")

if __name__ == "__main__":
    print("Simple factory example")
    print("-"*25)
    factory = UnitFactory()
    k = Kingdom(factory)
    elf_unit = k.recruit("ElfRider")
    print("Created an instance of :", elf_unit.__class__.__name__)

 

下列python代码改进了简单工厂模式,工厂不需要再维护大段if...else语句块,改为字典(黄色)维护;蓝色类方法调用:

class ElfRider:
    pass
class Knight:
    pass
class OrcRider:
    pass
class DwarfFighter:
    pass
class OrcRider:
    pass
class Fairy:
    pass
class Wizard:
    pass
class ElfLord:
    pass
class OrcFighter:
    pass


class UnitFactory:
    """A factory class to create game units.

    This is an example that shows how we can use Python classes (which are
    first-class objects) and a class method to represent a simple factory. In
    this example, the client does not instantiates factory. See the book
    mentioned at the top of this file for detailed explanation.

    :cvar units_dict: Python dictionary created as a class variable. This
            dictionary holds names (types) of the game units as its keys and
            the corresponding values are the concrete classes representing the
            game character.
    .. seealso:: `Kingdom` class and various classes like `ElfRider`, `Knight`
    """
    units_dict = {
        'elfrider': ElfRider,
        'knight': Knight,
        'dwarffighter': DwarfFighter,
        'orcrider': OrcRider,
        'fairy': Fairy,
        'wizard': Wizard,
        'elflord': ElfLord,
        'orcfighter': OrcFighter
    }

    @classmethod
    def create_unit(cls, unit_type):
        """Return an instance of a game unit.

        This is a class method and it uses the class variable unit_dict to
        create and return an instance of a game unit class (e.g. ElfRider(),
        Knight(), Dwarf() and so on.

        :arg unit_type: A string representing the unit type (e.g. 'elfrider')
        :return:Instance of a game unit.
        """
        key = unit_type.lower()
        return cls.units_dict.get(key)()


class Kingdom:
    """Class that uses a 'factory' to get an instance of a game character.

    :cvar UnitFactory factory: This is a class variable that represents
             UnitFactory class.

    .. seealso:: class `UnitFactory`
    """
    factory = UnitFactory

    def recruit(self, unit_type):
        """Recruit a new game unit, creating it first using a factory.

        This method recruits a new unit for the 'kingdom'. First it 'orders' a
        unit from the 'factory' which is a 'class variable'. Then pays the
        price and updates some record. The pay_gold and update_record methods
        are dummy, they just print some information.

        :arg string unit_type:  The type (name) of unit requested.
        :return: A game unit instance returned by the factory.
        """
        # ----------------------------------------------------------------------
        # For Python 2.7, type(self) is not same as self.__class__. So just to
        # make the code compatible with both Python 2.7 and 3.5, we will use
        # self.__class__ (supported even by v3.5) to retrieve the class.
        # ----------------------------------------------------------------------
        ## unit = type(self).factory.create_unit(unit_type) # disabled

        unit = self.__class__.factory.create_unit(unit_type)
        self.pay_gold(unit)
        self.update_records(unit)
        return unit

    def pay_gold(self, something):
        """Pay gold for the recruited unit (dummy method)."""
        print("GOLD PAID")

    def update_records(self, something):
        """Update some record to reflect new recruit(dummy method)."""
        print("Some logic (not shown) to update database of units")

if __name__ == "__main__":
    print("Simple factory example")
    print("-"*25)
    k = Kingdom()
    elf_unit = k.recruit("ElfRider")
    print("Created an instance of :", elf_unit.__class__.__name__)

 

抽象工厂模式:简单工厂只能实现一种规格的产品生产,我们可以将工厂做成抽象类,然后做出许多具体的产品工厂,这样就能根据不同需求制作出不同的产品规格。

在python中,抽象工厂模式的抽象类可以忽略,只保留那些具体的产品工厂。供代码使用:

import sys

# Some dummy classes to represent factory products (not documented)
class IronJacket:
    pass
class PowerSuit:
    pass
class MithrilArmor:
    pass
class GoldLocket:
    pass
class SuperLocket:
    pass
class MagicLocket:
    pass
class DwarfIronJacket:
    pass
class DwarfPowerSuit:
    pass
class DwarfMithrilArmor:
    pass
class DwarfGoldLocket:
    pass
class DwarfSuperLocket:
    pass
class DwarfMagicLocket:
    pass


class AccessoryFactory:
    """A factory base class to create various game accessories.

    This is an example that shows how we can use Python classes (which are
    first-class objects) and a class method to represent a simple factory. In
    this example, the client does not instantiates factory. See the book
    mentioned at the top of this file for detailed explanation.

    :cvar armor_dict: Python dictionary created as a class variable. This
            dictionary holds names of the armor accessories as its keys and
            the corresponding values are the concrete classes representing the
            armor accessory for the game units. This class variable may be
            overridden in subclasses.
    :cvar armor_dict: Similar to `armor_dict` , a dictionary created as a class
            variable to hold concrete classes representing the 'locket'
            accessory. This class variable may be
            overridden in subclasses.

    .. seealso:: `Kingdom.buy_accessories` , `DwarfKingdom`
                 Also review the code in `simplefactory_pythonic.py`
    """
    # Subclasses specify their own version of these dictionaries.
    armor_dict = {
        'ironjacket': IronJacket,
        'powersuit': PowerSuit,
        'mithril': MithrilArmor
    }
    locket_dict = {
        'goldlocket': GoldLocket,
        'superlocket': SuperLocket,
        'magiclocket': MagicLocket
    }

    @classmethod
    def create_armor(cls, armor_type):
        """Return an instance of an armor accessory

        This is a class method and it uses the class variable armor_dict to
        create and return an instance of an armor accessory (e.g. IronJacket(),
        PowerSuit() etc.

        :arg string armor_type: A string representing the armor type
        :return: Instance of an armor accessory such as IronJacket().
        """
        return cls.armor_dict.get(armor_type)()

    @classmethod
    def create_locket(cls, locket_type):
        """Return an instance of a locket accessory

        This is a class method and it uses the class variable locket_dict to
        create and return an instance of an armor accessory (e.g. GoldLocket(),
        DwarfGoldLocket() etc.

        :arg string armor_type: A string representing the armor type
        :return: Instance of an armor accessory such as GoldLocket().
        """
        return cls.locket_dict.get(locket_type)()


class DwarfAccessoryFactory(AccessoryFactory):
    """A factory for creating accessories customized for Dwarf game character.

    Redefines the class variables, armor_dict and locket_dict.

    .. seealso:: the superclass for more details.
    """
    # Redefine the accessory dictionaries.
    armor_dict = {
        'ironjacket': DwarfIronJacket,
        'powersuit': DwarfPowerSuit,
        'mithril': DwarfMithrilArmor
    }
    locket_dict = {
        'goldlocket': DwarfGoldLocket,
        'superlocket': DwarfSuperLocket,
        'magiclocket': DwarfMagicLocket
    }


class Kingdom:
    """Class that uses a 'factory' to create the desired accessory.

    :cvar factory: This is a class variable that represents
             AccessoryFactory class or its subclass.

    .. seealso:: class `AccessoryFactory`
    """
    # Define which factory class you want to use. (Redefined in subclasses)
    factory = AccessoryFactory

    def buy_accessories(self, armor_type, locket_type):
        """Create accessories using factories, pay gold and update record.

        Demonstrates how to use concrete factory classes to create accessory
        objects (without instantiating the factories)

        The pay_gold and update_records are just dummy methods.

        :arg string armor_type: Armor type to be created.
        :arg string locket_type: Locket type to be created
        .. seealso:: simplefactory_pythonic.py
        """
        # ----------------------------------------------------------------------
        # For Python 2.7, type(self) is not same as self.__class__. So just to
        # make the code compatible with both Python 2.7 and 3.5 we will use
        # self.__class__ (supported even by v3.5) to retrieve the class.
        # ----------------------------------------------------------------------
        ## armor = type(self).factory.create_armor(armor_type)  # disabled
        ## locket = type(self).factory.create_locket(locket_type) # disabled

        armor = self.__class__.factory.create_armor(armor_type)
        locket = self.__class__.factory.create_locket(locket_type)
        accessories = [armor, locket]
        self.pay_gold(accessories)
        self.update_records(accessories)
        self.print_info(armor, locket)

    def pay_gold(self, accessories):
        """Pay gold for the new accessories (dummy method)."""
        print("GOLD PAID")

    def update_records(self, accessories):
        """Update some record to reflect new accessories (dummy method)."""
        print("Updated database of accessories")

    def print_info(self, armor, locket):
        """Print some information on the newly created accessories

        :arg armor: Should be an instance of an armor class e.g. IronJacket()
        :arg locket: Should be an instance of an armor class e.g. GoldLocket()
        """
        print("Done with shopping in       :", self.__class__.__name__)
        print("  concrete class for armor  :", armor.__class__.__name__)
        print("  concrete class for locket :", locket.__class__.__name__)


class DwarfKingdom(Kingdom):
    """Class that represents imaginary Kingdom of The Great Dwarfs."""
    # Define which factory you want to use for this kingdom.
    factory = DwarfAccessoryFactory

if __name__ == '__main__':
    print("Buying accessories in default Kingdom...")
    k = Kingdom()
    k.buy_accessories("ironjacket", "goldlocket")
    print("-"*56)
    print("Buying accessories in DwarfKingdom...")
    dwarf_kingdom = DwarfKingdom()
    dwarf_kingdom.buy_accessories("ironjacket", "goldlocket")
View Code

 

适配器模式:适配器模式允许两个不兼容的接口之间的交互。通过自己定义的适配器,将类或库的不兼容接口转换为客户端代码希望的接口。

举例说明:当你的游戏程序到一定程度,一群开发人员想要和你合作完善这个游戏。他们同时带来了自己的一些游戏角色。

于是出现了矛盾的地方。你定义的游戏人物都有jump()函数方法,别的开发者的WoodElf类(木精灵)角色遇到jump方法不知道该怎么办,他们只有自己的leap(优雅跳)方法。而且他们的代码是不对外的

也就是说你只能修改你本身的代码。

此时可以定义一个适配器类,让你定义的类和他们的类能沟通。

class WoodElf:
    def leap(self):
        print("在WoodElf.leap中")
    
class WoodElfAdapter:
    def __init__(self,woodelf):
        self.woodelf=woodelf
    def jump(self):
        self.woodelf.leap()
   

黄色为原代码,不必改变;蓝色代码定义了一个适配器,我们使用适配器的实例,适配器有自己的jump方法:调用了woodelf的leap方法。

上述代码解决了一个问题,试想一下,如果有100种精灵,那么还得对100中分别进行适配吗?所以就需要将适配器进行“通用化”:


class ElfRider:
def jump(self):
print("在ElfRider.jump中")
class WoodElf:
def leap(self):
print("在WoodElf.leap中")
def climb(self):
print("在WoodElf.climb中")
class MountainElf:
def spring(self):
print("在MountainElf.spring中")





class WoodElfAdapter:
def __init__(self,adaptee,adaptee_method): #adaptee表示需要适配器类对象,
#第二个参数adaptee_method需要被适配的实例方法
self.foreign_unit=adaptee
self.jump=adaptee_method #将实例方法赋给jump,jump类似别名

def __getattr__(self,item):#此时适配器可以调用foreign_unit提供的方法
return getattr(self.foreign_unit,item)#可以调用第三方的类的方法,自己本身
#不定义

if __name__ =="__main__":
elf=ElfRider()
elf.jump()

wood_elf=WoodElf()
wood_elf_adapter=WoodElfAdapter(wood_elf,wood_elf.leap)
wood_elf_adapter.jump()
wood_elf_adapter.climb() #调用__getattr__,因为适配器类中并没有climb()

mountain_elf=MountainElf()
mountain_elf_adapter=WoodElfAdapter(mountain_elf,mountain_elf.spring)
mountain_elf_adapter.jump()

 

看结果体会调用过程:

在ElfRider.jump中
在WoodElf.leap中
在WoodElf.climb中
在MountainElf.spring中

上面的代码中,红色的为类似别名的适配器方法。如果有100个类似的方法需要定义怎么办?

可以借助内置方法setattr():

class OtherElf:
    def leap(self):
        print("在OtherElf.leap中")
    def hit(self):
        print("在OtherElf.hit中")
        
class ForeignUnitAdapter:
    def __init__(self,adaptee):
        self.foreign_unit=adaptee
    def __getattr__(self,item):
        return getattr(self,foreign_unit,item)
    def set_adapter(self,name,adaptee_method):
        setattr(self,name,adaptee_method)
        

if __name__ == '__main__':
    other_elf=OtherElf()
    other_elf_adapter=ForeignUnitAdapter(other_elf)
    other_elf_adapter.set_adapter('jump',other_elf.leap)
    other_elf_adapter.set_adapter('attack',other_elf.hit)
    other_elf_adapter.attack()
    other_elf_adapter.jump()  

结果:

在OtherElf.hit中
在OtherElf.leap中