我想编写一个模块(特定于框架),它将包装和扩展 Facebook PHP-sdk(https://github.com/facebook/php-sdk/)。我的问题是 - 如何以一种好的方式组织课程。
所以进入细节 - Facebook PHP-sdk 由两个类组成:
- BaseFacebook - 包含 sdk 所做的所有事情的抽象类
- Facebook - 扩展 BaseFacebook,并使用默认会话使用实现父抽象持久性相关方法
现在我要添加一些功能:
- Facebook 类替换,与框架会话类集成
- 运行 api 调用的速记方法,我主要使用(通过 BaseFacebook::api()),
- 授权方法,所以我不必每次都重写这个逻辑,
- 配置,从框架类中吸取,作为参数传递
- 缓存,与框架缓存模块集成
我知道有些地方出了问题,因为我有太多看起来不太正常的继承。将所有内容包装在一个“复杂扩展”类中似乎也太多了。我想我应该很少有工作在一起的类 - 但我遇到了这样的问题:如果缓存类没有真正扩展和覆盖 BaseFacebook::api() 方法 - 速记和身份验证类将无法使用缓存。
也许某种模式就在这里?您将如何组织这些类及其依赖项?
编辑 04.07.2012
与主题相关的代码位:
Facebook PHP-sdk 的基类是这样的:
abstract class BaseFacebook {
// ... some methods
public function api(/* polymorphic */)
{
// ... method, that makes api calls
}
public function getUser()
{
// ... tries to get user id from session
}
// ... other methods
abstract protected function setPersistentData($key, $value);
abstract protected function getPersistentData($key, $default = false);
// ... few more abstract methods
}
Normaly Facebook 类对其进行了扩展,并引入了这些抽象方法。我用我的替代品代替了它 - Facebook_Session 类:
class Facebook_Session extends BaseFacebook {
protected function setPersistentData($key, $value)
{
// ... method body
}
protected function getPersistentData($key, $default = false)
{
// ... method body
}
// ... implementation of other abstract functions from BaseFacebook
}
好的,然后我使用速记方法和配置变量对此进行更多扩展:
class Facebook_Custom extends Facebook_Session {
public function __construct()
{
// ... call parent's constructor with parameters from framework config
}
public function api_batch()
{
// ... a wrapper for parent's api() method
return $this->api('/?batch=' . json_encode($calls), 'POST');
}
public function redirect_to_auth_dialog()
{
// method body
}
// ... more methods like this, for common queries / authorization
}
我不确定,如果这对于单个类(授权/速记方法/配置)来说不是太多。然后是另一个扩展层——缓存:
class Facebook_Cache extends Facebook_Custom {
public function api()
{
$cache_file_identifier = $this->getUser();
if(/* cache_file_identifier is not null
and found a valid file with cached query result */)
{
// return the result
}
else
{
try {
// call Facebook_Custom::api, cache and return the result
} catch(FacebookApiException $e) {
// if Access Token is expired force refreshing it
parent::redirect_to_auth_dialog();
}
}
}
// .. some other stuff related to caching
}
现在这非常有效。Facebook_Cache 的新实例为我提供了所有功能。Facebook_Custom 中的速记方法使用缓存,因为 Facebook_Cache 覆盖了 api() 方法。但这是困扰我的事情:
- 我认为这是太多的继承。
- 这一切都非常紧密 - 就像看看我如何必须指定 'Facebook_Custom::api' 而不是 'parent:api',以避免 Facebook_Cache 类扩展上的 api() 方法循环。
- 整体混乱和丑陋。
再说一遍,这可行,但我只是在询问以更清洁和更智能的方式执行此操作的模式/方式。