如何使用抽象类而不是自定义组件的接口?

重生

我正在为 Yii2 开发一个文件管理器模块,其目标是为用户提供使用不同来源进行目录浏览的选项,例如

  • 本地目录
  • 保管箱
  • 一个驱动器
  • 谷歌云端硬盘

为了实现这一点,我编写了一个接口,该接口将由用户想要使用的不同适配器实现。例如,下面是来自具有常用功能的界面的几行代码:

<?php

namespace buttflattery\filemanager\adapters;

/**
 * File Manager Interface class
 */
interface DirectoryInterface
{

    public function listFolder(string $directory, array $sortParams);

    public function removeFile(string $file);

    public function createFolder(string $folder, string $parentDirectory);

    public function uploadFile(string $file, string $destinationDirectory);

    public function downloadFile(string $zipFile);

    public function renameFile(string $oldFile, string $newFile);

    public function moveFiles(array $filesList, string $destination);

    public function copyFiles(array $files, string $destination);

}

我从LocalDirectoryAdapter; 它通过配置文件作为模块的组件附加,

'modules' => [
    'filemanager' => [
        'class' => 'buttflattery\filemanager\Module',
        'components' => [
             'adapter' => [
                 'class' => 'buttflattery\filemanager\adapters\local\LocalDirectoryAdapter',
                 'rootDir' => 'tinyii-uploads'
             ]
        ],
    ],
],

一切正常,直到我在开始实施 Dropbox 适配器后遇到了一个情况。

有几种方法将使用完全相同的代码。例如,listFolder()在两个相同的LocalDirectoryAdapterDropoxAdapter

原因是因为有一个FileIndexer组件会查询文件树并将其写入一个 JSON 文件,然后所有的列表和浏览都是由FileIndexer组件通过该 JSON 文件完成的

那时,我想我需要将接口更改为一个abstract类,添加那些通用方法,并将这些方法保留为抽象方法,这些方法需要专门针对我正在使用的 Directory 源实现。这就是我不解的地方:

LocalDirectoryAdapter类被声明为

class LocalDirectoryAdapter extends Component implements DirectoryInterface{
}

一旦我将接口更改为抽象类,我就必须使用extend,在这种情况下,我无法扩展yii\base\Component该类。

我怎样才能解决这个问题?

詹姆士

您可以使用 aTrait而不是抽象类来处理此公共代码。使用 Trait 的一个原因是,它允许您保持类层次结构不变,而且还可以重用否则会重复的代码。

以下是将 trait 注入到你实现的类中的方法:

<?php
class LocalDirectoryAdapter extends yii\base\Component implements DirectoryInterface{
  use DirectoryTrait;

  public function removeFile(string $file) { }

  public function createFolder(string $folder, string $parentDirectory) { }

  public function uploadFile(string $file, string $destinationDirectory) { }

  public function downloadFile(string $zipFile) { }

  public function renameFile(string $oldFile, string $newFile) { }

  public function moveFiles(array $filesList, string $destination) { }

  public function copyFiles(array $files, string $destination) { }
}

和特质本身:

<?php
trait DirectoryTrait {
  public function listFolder(string $directory, array $sortParams) {
    //implement the listFolder things
  }
}

您甚至可以通过简单地排除该use AdapterTrait来选择性地选择让您的适配器使用或不使用 Trait 这是一个小的工作示例 ( trait.php)。看看如何DirectoryAdapterNoTrait不使用特性。

<?php
interface AdapterInterface {
    public function listFiles(string $dir);
}

trait AdapterTrait {
    public function listFiles(string $dir)
    {
        echo "Doing TRAIT listFiles" . PHP_EOL;
    }
}
class DirectoryAdapterTrait extends yii\base\Component implements AdapterInterface {
    use AdapterTrait;
}
class DirectoryAdapterNoTrait extends yii\base\Component implements AdapterInterface {
    public function listFiles(string $dir)
    {
        echo "NOT TRAIT listFiles" . PHP_EOL;
    }
}

$adapterTrait = new DirectoryAdapterTrait();
$adapterTrait->listFiles("some_dir");

$adapterNoTrait = new DirectoryAdapterNoTrait();
$adapterNoTrait->listFiles("some_dir");

echo PHP_EOL;

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

使用抽象类\接口

通用抽象类的自定义Jackson反序列化

如果我在实现工厂模式时使用抽象类而不是接口。还是工厂模式吗?

什么时候必须使用接口而不是抽象类?

Java的使用[接口/抽象类]

为什么要使用抽象类而不是接口?

为什么要使用空的抽象类而不是接口?

如何修改此代码以使用良好做法?(接口,特征,抽象类)

自定义gson序列化抽象类

C#接口,抽象类,强制继承的类而不是抽象类

使用继承(带有抽象类)在自定义框架中为子类提供方法子部分的更优雅的方法吗?

如何使用SilverStripe中的自定义类注入属于框架的接口

如何使不是其抽象类的子类的接口实现者的行为类似于该接口的抽象类?

仅使用抽象类部分实现接口时如何满足编译器?

如何从PHP中的抽象类获取接口名称

抽象类,类,接口

Grails-接口而不是抽象类

Django:如何级联在不同抽象类中定义的自定义管理器?

PHP使用抽象类还是接口?

如何在抽象类和接口之间进行选择

如何编写指定创建逻辑的接口或抽象类?

具有自定义批注的抽象类

如何使Django自定义用户模型成为抽象类

如何实现接口到抽象类的约束?

强制构造函数签名是使用抽象类而不是接口的有效理由吗?

与抽象类的接口

使用接口和抽象类

自定义构造函数输入到 AutoFixture 中的抽象类

如何检测接口和抽象类之间的区别?