我的程序需要做两件事。
从网页中提取内容。
使用网页进行处理。
但是,有很多网页,如Twitter和Facebook。
我应该这样做吗?def facebookExtract():
code here
def twitterExtract():
code here
def myspaceExtract():
code here
def facebookProcess():
code here
def twitterProcess():
code here
def myspaceProcess():
code here
或者,我应该上某种课吗?什么时候建议使用类,什么时候建议只使用函数?
答案 0 :(得分:16)
“我的程序需要做两件事。”
当你这样开始时,无法看到物体。你的观点不对。
改变你的想法。
“我的程序适用于”
这是OO的想法。你的程序使用什么“东西”?定义东西。那些是你的基础课程。每种东西都有一个类。
“我的程序从各种来源获取内容”
每个来源都有一个班级。
“我的程序显示内容”
这通常是这些东西的访问器方法和一些“报告”类的组合,它们收集部分内容以显示它。
当你开始定义“东西”而不是“do”时,你正在做OO编程。 OO适用于所有事物,因为每个程序都涉及“做”和“东西”。你可以选择“做”POV(可以是程序性的或功能性的),或者你可以选择“东西”POV(面向对象)。
答案 1 :(得分:11)
我最喜欢的经验法则:如果你有疑问(不言而喻的假设:“你是一个合理的人而不是狂热的人”;-),请制作并使用一些课程。我经常发现自己将最初编写为简单函数的代码重构为类 - 例如,任何时候简单函数与彼此通信的最佳方式都是全局变量,这是代码气味,强烈暗示系统的分解是不太好 - 通常重构OOP方式是一个合理的解决方法。
Python是多范式的,但它的核心范例是OOP(很像C ++)。当程序或功能方法(可能通过生成器和c)对于系统的某些部分来说是最佳的时,这通常是突出的 - 例如,静态函数也是代码气味,并且如果您的类具有任何大量的那些这是重构事物以避免这种要求的暗示。
所以,假设你对Python提供的所有范例都有丰富的把握 - 如果你仍然存在疑问,这表明你可能想要为系统的这一部分进行OOP!仅仅因为Python支持OOP甚至比它支持函数式编程等更全面。
从你的骨架代码来看,在我看来,每个提取/进程对都属于一个并且可能需要通信状态,所以一小部分具有提取和处理方法的类似乎很自然。
答案 2 :(得分:3)
这取决于你。在python中编程时,我个人试图远离Java风格的类。相反,我使用dicts和/或简单对象。
例如,在定义了这些函数(你在问题中定义的函数)之后,我会创建一个简单的dict,也许是这样的:
{ 'facebook' : { 'process' : facebookProcess, 'extract': facebookExtract },
.....
}
或者更好的是,使用内省来自动获取进程/提取函数:
def processor(sitename):
return getattr(module, sitename + 'Process')
def extractor(sitename):
return getattr(module, sitename + 'Extractor')
其中module
是当前模块(或具有这些功能的模块)。
将此模块作为对象:
import sys
module = sys.modules[__name__]
当然假设通用主函数执行如下操作:
figure out sitename based on input. get the extractor function for the site get processor function for the site call the extractor then the processor
答案 3 :(得分:2)
将尽可能多的常见内容放在一个函数中。一旦你考虑到尽可能多的因素,建立一个机制,分支到每个网站的相应功能。
一种可行的方法是使用python的if/else
子句,但是如果你有很多这样的函数,你可能想要更优雅的东西,比如
F = __import__('yourproject.facebookmodule')
这使您可以将特定于facebook的代码放在其自己的区域中。由于您传递了__import__()
一个字符串,您可以根据您正在访问的站点在运行时修改它,然后只需在您的通用工作程序代码中调用函数F.
答案 4 :(得分:1)
在有意义的情况下使用OOP,在更快地开发解决方案时以及在最终结果更易于阅读,理解和维护时使用OOP。
在这种情况下,可能有意义创建一个通用的Extractor接口/类,然后有Twitter,MySpace,Facebook等的子类,但这实际上取决于特定于站点的提取方式。这种抽象的想法是隐藏这些细节。如果你能做到,那就有意义了。如果你不能,你可能需要一种不同的方法。
也可以从程序解决方案的良好分解中获得类似的好处。
记住,在一天结束时,所有这些东西都只是工具。为那个特定的工作选择最好的工作,而不是挑选锤子,然后尝试将所有东西变成钉子。
答案 5 :(得分:1)
由于一些原因,我经常定义用于解决问题的类,我将在下面为我的思考建立一个示例。我没有关于混合OO模型和程序风格的任何内容,这通常更多地反映了你的工作社会而不是个人宗教。如果这是其他维护者所期望的,那么它通常可以为类层次结构设置程序外观。 (请原谅PHP语法。)
// batch process method
function MunchPages( $list_of_urls )
{
foreach( $list_of_urls as $url )
{
$muncher = PageMuncher::MuncherForUrl( $url );
$muncher->gather();
$muncher->process();
}
}
// factory method encaps strategy selection
function MuncherForUrl( $url )
{
if( strpos( $url, 'facebook.com' ))
return new FacebookPageMuncher( $url );
if( ... )
return new .... ;
}
// common tasks defined in base PageMuncher
class PageMuncher
{
function gather() { /* use some curl or what */ }
function process() {}
}
class FacebookPageMuncher extends PageMuncher
{
function process() { /* I do it 'this' way for FB */ }
}
class PageMuncherUtils
{
static function begin( $html, $context )
{
// process assertions about html and context
}
static function report_fail( $context ) {}
static function exit_retry( $context ) {}
}
// elsewhere I compose the methods in cases I don't wish to inherit them
class TwitterPageMuncher
{
function validateAnchor( $html, $context )
{
if( ! PageMuncherUtils::begin( $html, $context ))
return PageMuncherUtils::report_fail( $context );
}
}
class WeatherAPI
{
const URL = 'http://weather.net';
const URI_TOMORROW = '/nextday/';
const URI_YESTERDAY= '/yesterday/';
const API_KEY = '123';
}
class WeatherService
{
function get( $uri ) { }
function forecast( $dateurl ) { }
function alerts( $dateurl )
{
return new WeatherAlert(
$this->get( WeatherAPI::URL.$date
."?api=".WeatherAPI::API_KEY ));
}
}
class WeatherAlert
{
function refresh() {}
}
// exercise:
$alert = WeatherService::alerts( WeatherAPI::URI_TOMORROW );
$alert->refresh();