【发布时间】:2014-03-19 02:47:56
【问题描述】:
我注意到一些最近流行的 PHP 库(例如 Laravel)中的一个常见模式,其中 API 大量基于静态类和方法。此类 API 外观的典型示例:
Logger::note('Handle routes for the welcome area of the site.');
Route::match('/welcome/:id', function ($id) {
$name = Model::from('users')->get('name')->where('id', $id);
$body = Template::body('templates/wecome.tpl', array('name' => $name));
HTTP::respond(200, $body);
}
代码看起来可读性很好,并且 Composer 自动加载了 5 个不同的静态类,所以乍一看,这似乎是一个很有吸引力的使用模式。我的问题是,对于那些在设计 API 方面更有经验的人来说,随着事情的扩大,这似乎是一种好方法吗?
举个例子,我可以立即看到一些笨拙的东西,例如,如果我想要保留多个日志。在非静态模式中,我可以这样做:
$debugLog = new Logger('logs/debug.log');
$errorLog = new Logger('logs/errors.log');
Route::match('/welcome/:id', function ($id) {
$debugLog->note('Handle routes for the welcome area of the site.');
$name = Model::from('users')->get('name')->where('id', $id);
if (empty($name)) {
$errorLog->warn('Name is empty!');
}
}
但这很难在许多不同的方法和文件之间共享。
#file1.php
Route::match('/welcome/:id', function ($id) {
$debugLog = new Logger('logs/debug.log');
$debugLog->note('Handle routes for the welcome area of the site.');
//etc
}
#file2.php
Route::match('/news', function ($id) {
$debugLog = new Logger('logs/debug.log');
$debugLog->note('Handle routes for the news area of the site.');
if ($error) {
$errorLog = new Logger('logs/errors.log');
$errorLog->warn('There is some problem: '.$error);
}
}
现在我不得不重复自己,以便在所有地方实例化非静态类,这至少会使代码混乱,并且可以说使其更难维护。
但是,另一方面,every-class-a-static 方法似乎也不容易扩展。假设我想使用静态 API 拥有多个日志;我可以尝试一些单例和工厂...
Logger::get('debug')->note('Handle routes for the welcome area of the site.');
Logger::get('errors')->note('Danger!');
但这似乎只是将 API 从方法名称转换为字符串参数(可能拼写错误等)。如果我想要两个不同的“调试”记录器怎么办?
无论我采用哪种方式,一方面基于静态,另一方面基于实例,随着模式使用的增长,我似乎遇到了限制。
鉴于我不想用重复的实例化代码填充我的应用程序,但我还希望在现有类的基础上灵活地扩展更多种类的类,关于最佳方法的任何建议?
【问题讨论】:
-
好吧,你可能想读这个:r.je/static-methods-bad-practice.html
-
@djay +1 为那篇文章,它完美地阐明了为什么基于静态的 API 很受欢迎,但最终是个坏主意。
-
所有基于静态类的设计模式都有一个名称:anti-patterns
标签: php oop design-patterns software-design