简体   繁体   English

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

[英]How to use an abstract class instead of an interface for a custom component?

I'm working on a File Manager module for Yii2 where the goal is to provide the user with an option to use different sources for directory browsing, like我正在为 Yii2 开发文件管理器模块,其目标是为用户提供使用不同来源进行目录浏览的选项,例如

  • Local Directory本地目录
  • Dropbox投递箱
  • One Drive一个驱动器
  • Google Drive谷歌云端硬盘

To accomplish this, I wrote an interface which will be implemented by different adapters that the user wants to use.为此,我编写了一个接口,该接口将由用户想要使用的不同适配器实现。 For example, here are a few lines of code from the interface with common functions:例如,这里有几行代码来自具有常用功能的接口:

<?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);

}

I started with the LocalDirectoryAdapter ;我从LocalDirectoryAdapter开始; it's attached as a component with the module via a config file,它通过配置文件作为组件附加到模块中,

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

It all works fine, until I came across a situation after I started implementing the Dropbox adapter.一切正常,直到我开始实施 Dropbox 适配器后遇到了一种情况。

There are a couple of methods that will be using exactly the same code.有几种方法将使用完全相同的代码。 For instance, the listFolder() is the same in both LocalDirectoryAdapter and DropoxAdapter .例如, listFolder()LocalDirectoryAdapterDropoxAdapter中是相同的。

The reason is because there is a FileIndexer component which queries the file tree and writes it down to a JSON file, and then all the listing and browsing is done via that JSON file by the FileIndexer component.原因是因为有一个FileIndexer组件查询文件树并将其写入 JSON 文件,然后所有的列表和浏览都是由FileIndexer组件通过该 JSON 文件完成的。

At that point, I figured I needed to change the interface to an abstract class, add those methods that are common, and leave those methods as abstract which will need to be implemented specifically to the Directory source I am using.那时,我想我需要将接口更改为abstract class,添加那些常见的方法,并将这些方法保留为抽象,这些方法需要专门针对我正在使用的目录源实现。 That is where I got puzzled:这就是我感到困惑的地方:

The LocalDirectoryAdapter class is declared as LocalDirectoryAdapter class 被声明为

class LocalDirectoryAdapter extends Component implements DirectoryInterface{
}

Once I change the interface to an abstract class, I am bound to use extend , and in that case, I cant extend the yii\base\Component class.一旦我将接口更改为抽象 class,我就必须使用extend ,在这种情况下,我无法扩展 yii yii\base\Component class。

How can I get around this problem?我怎样才能解决这个问题?

You can make your abstract adapter extend the yii\base\Component then by extending your abstract adapter the child class will also inherit from Component.您可以让您的抽象适配器扩展yii\base\Component ,然后通过扩展您的抽象适配器,子 class 也将从 Component 继承。

For example like this例如像这样

abstract class BaseDirectoryAdapter extends Component
{
}

class LocalDirectoryAdapter extends BaseDirectoryAdapter
{
}

But I think it's not a good practice to force usage of your abstract base class.但我认为强制使用抽象基础 class 并不是一个好习惯。 You don't know what adapters might be implemented in future.您不知道将来可能会实现哪些适配器。

What you can do is to use both.您可以做的是同时使用两者。 The interface that would define minimal requirements for adapter and abstract base class that would provide standard impelmentations for common methods.该接口将定义适配器和抽象基 class 的最低要求,为常用方法提供标准实现。

interface DirectoryInterface
{
}

abstract class BaseDirectoryAdapter extends Component implements DirectoryInterface
{
}

class LocalDirectoryAdapter extends BaseDirectoryAdapter
{
}

This allows you to benefit from implementations in BaseDirectoryAdapter but doesn't force you to use it.这使您可以从 BaseDirectoryAdapter 中的实现中受益,但不会强迫您使用它。

Yii uses this approach, you can for example see it with yii\db\ActiveRecord , yii\db\BaseActiveRecord and yii\db\ActiveRecordInterface . Yii 使用这种方法,例如,您可以使用 yii yii\db\ActiveRecordyii\db\BaseActiveRecord和 yii yii\db\ActiveRecordInterface来查看它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM