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(' ', '_')
RomanceBook
和FictionBook
类都继承自同一个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
的所有行为,就像一本“真实的”浪漫书。如果我将其类别切换为“小说”,它将再次切换其类,依此类推。
我们如何修改示例代码才能使其正常工作?
答案 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