一般编程问题。什么时候使用OOP?

时间:2009-10-29 03:33:55

标签: python oop function

我的程序需要做两件事。

  1. 从网页中提取内容。

  2. 使用网页进行处理。

  3. 但是,有很多网页,如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
    

    或者,我应该上某种课吗?什么时候建议使用类,什么时候建议只使用函数?

6 个答案:

答案 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.

更多相关信息: http://effbot.org/zone/import-confusion.htm

答案 4 :(得分:1)

在有意义的情况下使用OOP,在更快地开发解决方案时以及在最终结果更易于阅读,理解和维护时使用OOP。

在这种情况下,可能有意义创建一个通用的Extractor接口/类,然后有Twitter,MySpace,Facebook等的子类,但这实际上取决于特定于站点的提取方式。这种抽象的想法是隐藏这些细节。如果你能做到,那就有意义了。如果你不能,你可能需要一种不同的方法。

也可以从程序解决方案的良好分解中获得类似的好处。

记住,在一天结束时,所有这些东西都只是工具。为那个特定的工作选择最好的工作,而不是挑选锤子,然后尝试将所有东西变成钉子。

答案 5 :(得分:1)

由于一些原因,我经常定义用于解决问题的类,我将在下面为我的思考建立一个示例。我没有关于混合OO模型和程序风格的任何内容,这通常更多地反映了你的工作社会而不是个人宗教。如果这是其他维护者所期望的,那么它通常可以为类层次结构设置程序外观。 (请原谅PHP语法。)

  • 我正在开发策略,我可以遵循通用模型。因此,对您的任务进行可能的建模可能涉及获取一些东西来咀嚼传递的URL。如果您想要简化外部逻辑并删除条件,则此方法有效。这表明我可以将DNRY用于gather()方法。

    // 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 );
        }
    }
    

  • 我想组织我的代码以向维护者传达更广泛的意义。考虑一下,如果我有一个远程服务我正在接口,我可能会在他们的界面中潜入不同的API,我想将这些例程分组到类似的主题中。下面,我展示了一个示例,我喜欢定义一个定义公共常量的类,一个定义基本服务方法的类,以及一个更具体的天气警报类,因为警报应该知道如何刷新自己,它比天气更具体服务本身,但也利用WeatherAPI常量。

    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();