如何切换类

时间:2017-12-01 01:59:50

标签: python

class Book(object):
    def __init__(self, title):
        self.title = title

    def setCategory(self, category):
        self.category = category


class RomanceBook(Book):
    def __init__(self, title):
        super(RomanceBook, self).__init__(title)
        self.category = 'romance'

    def getTitle(self):
        return self.title.upper()


class FictionBook(Book):
    def __init__(self, title):
        super(FictionBook, self).__init__(title)
        self.category = 'fiction'

    def getTitle(self):
        return self.title.lower().replace(' ', '_')

RomanceBookFictionBook类都继承自同一个Book类。这两个类都有getTitle()方法,它返回书的标题。 RomanceBook使用字母大写返回标题,而FictionBook类使用小写返回标题:

romance_book = RomanceBook('Love Story')
print romance_book, romance_book.getTitle() 

fiction_book = FictionBook('Star Wars')
print fiction_book.getTitle()

打印:

<__main__.RomanceBook object at 0x108d37610> LOVE STORY
<__main__.FictionBook object at 0x108d37650> star_wars

现在我继续将category实例的fiction_book属性从'fiction'更改为romance

fiction_book.setCategory('romance')

如果fiction_book实例在更改FictionBook属性的同时将其类从RomanceBook切换到category,那将会很棒。然后它将继承RomanceBook的所有行为,就像一本“真实的”浪漫书。如果我将其类别切换为“小说”,它将再次切换其类,依此类推。

我们如何修改示例代码才能使其正常工作?

4 个答案:

答案 0 :(得分:1)

有可能更好的方法来做你想做的事情而不是类切换(可能类似于strategy pattern)但是如果你真的想这样做,你可以分配给实例__class__

class Book(object):
    def __init__(self, title):
        self.title = title

    def setCategory(self, category):
        self.category = category
        self.__class__ = classes[category] # IMPORTANT


class RomanceBook(Book):
    def __init__(self, title):
        super(RomanceBook, self).__init__(title)
        self.category = 'romance'

    def getTitle(self):
        return self.title.upper()


class FictionBook(Book):
    def __init__(self, title):
        super(FictionBook, self).__init__(title)
        self.category = 'fiction'

    def getTitle(self):
        return self.title.lower().replace(' ', '_')

classes = {
  'romance': RomanceBook, # IMPORTANT
  'fiction': FictionBook, # IMPORTANT
}

或者,如果您想使用元类自动添加到classes

classes = {}

class BookMetaclass(type):
  def __new__(cls, name, bases, attrs):
          new_class = type.__new__(cls, name, bases, attrs)
          if name != "Book":
            classes[new_class.category] = new_class

          return new_class

class Book(object, metaclass=BookMetaclass):
    def __init__(self, title):
        self.title = title

    def setCategory(self, category):
        self.category = category
        self.__class__ = classes[category]

...

策略模式示例:

class Book(object):
    title_funcs = {
      'romance': lambda title: title.upper(),
      'fiction': lambda title: title.lower().replace(' ', '_'),
    }

    def __init__(self, category, title):
        self.category = category
        self.title = title

    def setCategory(self, category):
        self.category = category

    def getTitle(self):
      return self.title_funcs[self.category](self.title)

答案 1 :(得分:1)

这可以在不同的变体中完成,但基本上是关于委派方法:

class RomanceBookSupport:

    @staticmethod
    def getTitle(book):
        return book.title.upper()


class FictionBookSupport:

    @staticmethod
    def getTitle(book):
        return book.title.lower().replace(' ', '_')


SUPPORTMAP = {
    'romance' : RomanceBookSupport,
    'fiction' : FictionBookSupport
}


class Book(object):
    def __init__(self, title):
        self.title = title

    def setCategory(self, category):
        self.category = category

    def getTitle(self):
        return SUPPORTMAP[self.category].getTitle(self)


romance_book = Book('Love Story')
romance_book.setCategory('romance')
print romance_book, romance_book.getTitle() 

fiction_book = Book('Star Wars')
fiction_book.setCategory('fiction')
print fiction_book.getTitle()

fiction_book.setCategory('romance')
print fiction_book.getTitle()

答案 2 :(得分:0)

这应该是你想要的,通过将getTitle方法提取到基类并动态决定应该使用哪个策略:

class Book(object):
    def __init__(self, title):
        self.title = title

    def setCategory(self, category):
        self.category = category

    def getTitle(self):

        if self.category == 'romance':
            return self.title.upper()
        elif self.category == 'fiction':
            return self.title.lower().replace(' ', '_')
        else:
            raise NotImplementedError()


class RomanceBook(Book):
    def __init__(self, title):
        super(RomanceBook, self).__init__(title)
        self.category = 'romance'


class FictionBook(Book):
    def __init__(self, title):
        super(FictionBook, self).__init__(title)
        self.category = 'fiction'


romance_book = RomanceBook('Love Story')
print(romance_book.getTitle())

fiction_book = FictionBook('Star Wars')

print(fiction_book.getTitle())

fiction_book.setCategory('romance')

print(fiction_book.getTitle())

答案 3 :(得分:0)

另一种可能性是在两者之间使用映射库; GitHub

from mapper.object_mapper import ObjectMapper


class Book(object):
    def __init__(self, title):
        self.title = title

    def setCategory(self, category):
        self.category = category


class RomanceBook(Book):
    def __init__(self, title=None):
        super(RomanceBook, self).__init__(title)
        self.category = 'romance'

    def getTitle(self):
        return self.title.upper()


class FictionBook(Book):
    def __init__(self, title=None):
        super(FictionBook, self).__init__(title)
        self.category = 'fiction'

    def getTitle(self):
        return self.title.lower().replace(' ', '_')


def new_book_type(book: Book, new_type):
    mapper = ObjectMapper()
    mapper.create_map(type(book), new_type)
    return mapper.map(book, new_type)

romance_book = RomanceBook('Love Story')
print (romance_book, romance_book.getTitle() )

fiction_book = FictionBook('Star Wars')
print(fiction_book, fiction_book.getTitle())

romantic_star_wars = new_book_type(fiction_book, RomanceBook)
print(romantic_star_wars, romantic_star_wars.getTitle())

产量

<__main__.RomanceBook object at 0x7fdf6e69ac50> LOVE STORY
<__main__.FictionBook object at 0x7fdf6d1a0a90> star_wars
<__main__.RomanceBook object at 0x7fdf6d1a0b00> STAR WARS