在实例化时将类转换为子类
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在实例化时将类转换为子类相关的知识,希望对你有一定的参考价值。
我正在编写一个查询Mediawiki API的框架。我有一个Page
类,代表维基上的文章,我也有一个Category
类,这是一个Page
与更具体的方法(如能够计算该类别中的成员数量。我也有方法Page#category?
通过查询API来确定文章的命名空间,确定实例化的Page
对象是否实际上代表了Mediawiki类别页面。
class Page
def initialize(title)
# do initialization stuff
end
def category?
# query the API to get the namespace of the page and then...
namespace == CATEGORY_NAMESPACE
end
end
class Category < Page
# ...
end
我想要做的是能够检测我的框架的用户是否尝试使用Page对象(即Page.new("Category:My Category")
)实例化Mediawiki类别,如果是,则直接从实例化Category
对象而不是Page
对象Page
构造函数。
在我看来,这应该是可能的,因为它让人想起Rails中的单表继承,但我不知道如何让它工作。
好的,有几件事:
您无法将类A
的实例转换为A
的子类B
的实例。至少,不是自动的。 B
可以(并且通常会)包含A
中不存在的属性,它可以具有完全不同的构造函数等。因此,AFAIK,没有OO语言将允许您以这种方式“转换”类。
即使在静态类型语言中,当你实例化B
,然后将它分配给a
类型的变量A
时,它仍然是B
的实例,它不会被转换为它的祖先类。
Ruby是一种具有强大反射功能的动态语言,因此您可以随时决定在运行时实例化哪个类 - 检查一下:
puts "Which class to instantiate: "
class_name = gets.chomp
klass = Module.const_get class_name
instance = klass.new
因此,这里不需要任何转换 - 只需首先实例化您需要的类。
另一件事:正如我在评论中提到的,方法category?
是完全错误的,因为它违反了OOP原则。在Ruby中,您可以 - 并且应该 - 使用方法is_a?
,因此您的检查将如下所示:
if instance.is_a? Category
puts 'Yes, yes, it is a category!'
else
puts "Nope, it's something else."
end
这只是冰山一角,还有更多关于实例化不同类的内容,而我在评论中链接的另一个问题可能是一个很好的起点,尽管有些代码示例可能会让您感到困惑。但绝对值得了解它们。
编辑:重新阅读更新后的问题后,在我看来,正确的方法是创建一个工厂类,让它检测并实例化不同的页面类型。因此,用户不会直接调用Page.new
,而是调用类似的东西
MediaWikiClient.get_page "Category:My Category"
和get_page
方法将实例化相应的类。
为什么不这样的?能够做到这一点是一个足够的理由去做!
class Page
def self.new(title)
if self == Page and is_category?(title)
Category.new(title)
else
super
end
end
def self.is_category?(title)
# ... (query the API etc.)
end
def initialize(title)
# do initialization stuff
end
def category?
# query the API to get the namespace of the page and then...
namespace == CATEGORY_NAMESPACE
end
end
class Category < Page
# ...
end
您可以定义一个实例化类并返回实例的方法。这被称为Factory Pattern
class PageFactory
def create(title) # the pattern uses "create".. but "new" is more Ruby' style
namespace = title[/A[^:]+(?=:)/]
# matches the prefix, up to and excluding the first colon.
if namespace == CATEGORY_NAMESPACE
Category.new(title)
else
Page.new(title)
end
end
end
class ClientClass
def do_something()
factory = PageFactory.new
my_page = factory.create('Category:Foo')
my_page.do_something()
end
end
以上是关于在实例化时将类转换为子类的主要内容,如果未能解决你的问题,请参考以下文章