唐山网站建设

设为主页 加入收藏 繁體中文

静态类的原罪

%3Cp%3E

黑格尔有句名言:存在即公道。以此为论据的话,静态类的使用必定有其公道性。不过物极必反,1旦代码过于依托静态类,其劣化的解决则不可避免。这就比如罂粟作为1种草本植物,有其在药理上的价值,但假设肆无忌惮的大量使用,它就变成了毒品。

甚么是静态类

所谓静态类指的是无需实例化成对象,直接通过静态方式调用的类。代码以下:


class Math
{
    public static function ceil($value)
    {
        return ceil($value);
    }

    public static function floor($value)
    {
        return floor($value);
    }
}

?>

此时类所扮演的角色更像是命名空间,这或许是很多人喜欢使用静态类最直接的缘由。

静态类的题目

本质上讲,静态类是面向进程的,由于通常它只是机械的把本来面向进程的代码集合到1起,固然结果是以类的方式存在,但此时的类更像是1件天子的新衣,所以可以说静态类实际上是披着面向对象的壳儿,干着面向进程的事儿。

面向对象的设计原则之1:针对接口编程,而不是针对实现编程。这有甚么不同?打个比方来讲:抛开价格因素,你喜欢独立显卡的电脑还是集成显卡的电脑?我想尽大多数人会选择独立显卡。独立显卡可以看做是针对接口编程,而集成显卡就便可以够看做是针对实现编程。如此说来针对实现编程的弊端就跃然纸上了:它丧失了变化的可能性。

下面杜撰1个文章治理系统的例子来具体说明1下:


class Article
{
    public function save()
    {
        ArticleDAO::save();
    }
}

?>

Article实现必要的领域逻辑,然后把数据持久化交给ArticleDAO往做,而ArticleDAO是1个静态类,就仿佛焊在主板上的集成显卡1样难以改变,假定我们为了测试代码可能需要Mock掉ArticleDAO的实现,但由于调用时使用的是静态类的名字,同等于已绑定了具体的实现方式,Mock几近不可能,固然,实际上有1些方法可以实现:


class Article
{
    private static $dao = 'ArticleDAO';

    public static funciton setDao($dao)
    {
        self::$dao = $dao;
    }

    public static function save()
    {
        $dao = self::$dao;

        $dao::save();
    }
}

?>

有了变量的参与,可以在运行时设定具体使用哪个静态类:


Article::setDao('MockArticleDAO');

Article::save();

?>

固然这样的实现方式看似解决了Mock的题目,但是首先它修改的原本的代码,背背了开闭原则,其次它引进了静态变量,而静态变量是共享的状态,有可能会干扰其它代码的履行,所以其实不是1个完善的解决方案。

补充说明,利用动态语言的特性,实在可以简单的通过require1个不同的类定义文件来实现Mock,但这样做一样有弊端,假想我们在脚本里需要屡次变换实现方式,但实际上我们只有1次require的机会,否则就会出现重复定义的毛病。

注:某些情况下,利用静态延迟绑定也能够进步静态类的可测试性,参考PHPUnit。

对象的价值

假设放弃静态类,转而使用对象,应当如何实现文章治理系统的例子?代码以下:


class Article
{
    private $dao;

    public function __construct($dao = null)
    {
        if ($dao === null) {
            $dao = new ArticleDAO();
        }

        $this->setDao($dao);
    }

    public function setDao($dao)
    {
        $this->dao = $dao;
    }

    public function save()
    {
        $this->dao->save();
    }
}

?>

实际上,这里用到了人们常说的依托注进技术,通过构造器或Setter注进依托的对象:


$article = new Article(new MockArticleDAO());

$article->save();

?>

对象有自己的状态,不会产生共享状态干扰其它代码的履行的情况。

固然,静态类有好的1面,比如说很合适实现1些无状态的工具类,但多数时候,我的主观偏向很明确,多用对象,少用静态类,避免系统过早的固化。顺便说1句,希看别有人告知我静态类比对象快之类的说教,谢谢。(来源:火丁笔记)

唐山网站建设www.fw8.net%3C%2Fp%3E
TAG:代码,方式,对象,状态,静态
评论加载中...
内容:
评论者: 验证码: