黑格尔有句名言:存在即合理。以此为论据的话,静态类的使用必然有其合理性。不过物极必反,一旦代码过于依赖静态类,其劣化的解决则不可避免。这就好比罂粟作为一种草本植物,有其在药理上的价值,但如果肆无忌惮的大量使用,它就变成了毒(和谐)品。
什么是静态类
所谓静态类指的是无需实例化成对象,直接通过静态方式调用的类。代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
<?php class Math
{
public static function ceil ( $value )
{
return ceil ( $value );
}
public static function floor ( $value )
{
return floor ( $value );
}
} ?> |
此时类所扮演的角色更像是命名空间,这或许是很多人喜欢使用静态类最直接的原因。
静态类的问题
本质上讲,静态类是面向过程的,因为通常它只是机械的把原本面向过程的代码集合到一起,虽然结果是以类的方式存在,但此时的类更像是一件皇帝的新衣,所以可以说静态类实际上是披着面向对象的壳儿,干着面向过程的事儿。
面向对象的设计原则之一:针对接口编程,而不是针对实现编程。这有什么不同?打个比方来说:抛开价格因素,你喜欢独立显卡的电脑还是集成显卡的电 脑?我想绝大多数人会选择独立显卡。独立显卡可以看做是针对接口编程,而集成显卡就就可以看做是针对实现编程。如此说来针对实现编程的弊端就跃然纸上了: 它丧失了变化的可能性。
下面杜撰一个文章管理系统的例子来具体说明一下:
1
2
3
4
5
6
7
8
9
10
11
|
<?php class Article
{
public function save()
{
ArticleDAO::save();
}
} ?> |
Article实现必要的领域逻辑,然后把数据持久化交给ArticleDAO去做,而ArticleDAO是一个静态类,就好像焊在主板上的集成 显卡一样难以改变,假设我们为了测试代码可能需要Mock掉ArticleDAO的实现,但因为调用时使用的是静态类的名字,等同于已经绑定了具体的实现 方式,Mock几乎不可能,当然,实际上有一些方法可以实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
<?php class Article
{
private static $dao = 'ArticleDAO' ;
public static funciton setDao( $dao )
{
self:: $dao = $dao ;
}
public static function save()
{
$dao = self:: $dao ;
$dao ::save();
}
} ?> |
有了变量的介入,可以在运行时设定具体使用哪个静态类:
1
2
3
4
5
6
7
|
<?php Article::setDao( 'MockArticleDAO' );
Article::save(); ?> |
虽然这样的实现方式看似解决了Mock的问题,但是首先它修改的原有的代码,违反了开闭原则,其次它引入了静态变量,而静态变量是共享的状态,有可能会干扰其它代码的执行,所以并不是一个完美的解决方案。
补充说明,利用动态语言的特性,其实可以简单的通过require一个不同的类定义文件来实现Mock,但这样做同样有弊端,设想我们在脚本里需要多次变换实现方式,但实际上我们只有一次require的机会,否则就会出现重复定义的错误。
注:某些情况下,利用静态延迟绑定也可以提高静态类的可测试性,参考PHPUnit。
对象的价值
如果放弃静态类,转而使用对象,应该如何实现文章管理系统的例子?代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
<?php 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注入依赖的对象:
1
2
3
4
5
6
7
|
<?php $article = new Article( new MockArticleDAO());
$article ->save();
?> |
对象有自己的状态,不会发生共享状态干扰其它代码的执行的情况。
…
当然,静态类有好的一面,比如说很适合实现一些无状态的工具类,但多数时候,我的主观倾向很明确,多用对象,少用静态类,避免系统过早的固化。顺便说一句,希望别有人告诉我静态类比对象快之类的说教,谢谢。
(转载至微信:PHP老杨,供学习参考之用)
相关推荐
静态类是一种声明为 static 类型的 且仅包含静态成员的类 不能使用 new 关键字创建静态类的实例 静态类在加载包含该类的程序或命名空间时由 NET Framework 公共语言运行库 CLR 自动加载 静态类和类成员用于创建无需...
JS定义静态类,可以看看,应该很容易看懂
直接调用类方法量:class::attribute/function,无论是静态/非静态都可以,静态static:声明类成员或方法为 static,就可以不实例化类而直接访问,不能通过一个对象来访问其中的静态成员(静态方法除外),静态成员属于类,不...
Java中的静态变量静态方法静态块与静态类.docx
wmp播放器静态类模块.rar wmp播放器静态类模块.rar wmp播放器静态类模块.rar wmp播放器静态类模块.rar wmp播放器静态类模块.rar wmp播放器静态类模块.rar
Visual Studio2012链接MySQL的静态类,all文件,粘贴复制至VS2012,导入all文件即可
以此为论据的话,静态类的使用必然有其合理性。不过物极必反,一旦代码过于依赖静态类,其劣化的结局则不可避免。这就好比罂粟作为一种草本植物,有其在药理上的价值,但如果肆无忌惮的大量使用,它就变成了毒品。 ...
易语言源码易语言wmp播放器静态类模块源码.rar
一个 自己 写的 jar 包,含有 Java 调用 Liunx 的静态类;文件的创建,读取,上传的静态类,和筛选目录下文件的静态类,包括源代码。
针对SQL数据操作,定义数据表为静态类和公共属性,实现通用的增删改查的操作,同时定义了自增字段及键值字段,自动实现更新或添加。十分方便的建立一个数据表的对象,使数据操作变得简单。
c#面向对象静态类、构造方法、静态方法介绍,有功能介绍,详细的执行方法和过程,可以让新人对编程语言快速入门。熟悉应用变量、静态变量、方法、静态方法,读取、处理、写入等功能实现,实现举一反三。
包含一些常用的操作类,大都是静态类,加密解密,反射操作,动态编译,硬件信息,字符串扩展方法,日期时间扩展操作,大文件拷贝,图像裁剪,验证码,断点续传,实体映射等常用封装。
远程网络教学系统静态类图 可作为初学者的参考
PHP生成静态类
易语言wmp播放器静态类模块源码,wmp播放器静态类模块,方法_创建,方法_关闭,读_属性_地址,写_属性_地址,读_属性_打开状态,读_属性_播放状态,方法_取控制,方法_取设定,方法_取当前媒体,方法_置当前媒体,...
面向对象模拟静态类和构造对象面向对象模拟静态类和构造对象面向对象模拟静态类和构造对象面向对象模拟静态类和构造对象
web服务 asp mvc 静态类 data contact