1

我已经写了几节课,并且在我应该做什么的道路上遇到了一个岔路口。我的基本问题是,如何避免在具有非常相似功能的类之间重复我的代码?特质现在对我来说不是一个选择,而且我认为它们在这里不会有太大帮助。

我实现了以下类。


    //either a directory or a file on the file system
    class FileSystem_Object{
        //the size of the class in bytes
        public function getSize(){}

        //same as phps native realpath
        public function getRealPath(){}
    }

    //a zip file on the file system, e.g. files that end in .zip extension.
    class FileSystem_Object_Zip extends FileSystem_Object{ 
        //returns size of all files if they were to be uncompressed, in bytes
        public function getUncompressedSize(){}
    }

    //a singleton file that keeps track of only one object copy of a file
    class FileSystem_Manager{}

这些类为我提供了一些 SPLFileObject 类型的功能。我可以做以下类型的事情


    $object = 
        FileSystem_Manager::getInstance()
        ->getFileSystemObjecT( '/some/path/to/file/or/directory/' );


每次我调用 getFileSystemObject 方法时,它要么返回一个新的类对象,要么返回一个已经分配给该路径的对象,从而避免我创建多个指向文件系统上相同路径的对象。(也许不是最好的主意,但这就是我的想法。)

这是我们解决问题的地方。

我有另一组用于“锁定”对象的类。现在,我锁定的唯一对象是 filesystem_objects,无论它们是目录还是文件。通过根据试图锁定它的 php 进程的进程 ID 为文件创建一个锁定文件,这很简单。



    inteface Lockable_Object{

        public functon getLockableIdentifier();
    }

    class Lockable_FileSystemObject implements Lockable_Object{

        /**
         * I return a false here if the file doesn't exist
         * so any other processes trying to lock this file will
         * know they can no longer lock it because it has moved
         * or been renamed for some reason.
         */

        public functon getLockableIdentifier(){ 
            if( file_exists( $this->_fullFilePath ) ){ 
                return $this->getRealPath();
            } 
            return false;
        }
    }


我现在面临的问题是我想创建一个也可以锁定的 Zip 文件对象,并且我希望能够锁定几乎任何文件/目录,但我不想复制代码。我应该做以下哪一项



    //Option 1
    class Lockable_Object_Zip extends FileSystem_Object_Zip 
                              implements Lockable_Object{
        //In here I would have to duplicate the getLockableIdentifier method and do that
        //for every file type i decide to make in the future
    }

    //Option 2
    class Lockable_Object_Zip extends Lockable_FileSystemObject
        //In here I would have to duplicate all the zip functionality coded into
        //FileSystem_Object_Zip 
    }

    //Option 3
    class FileSystem_Object implements Lockable_Object{
         //build in the 'lockablity' into the base class
    }


现在我倾向于选项 3,但我不想这样做的唯一原因是因为那时我必须在我想使用文件系统的东西时拥有我的库的“储物柜”部分;它会更紧密地耦合。

我相信你会对设计有意见,有些人会说“SplFileObject 做了所有/大部分”。我在这里包含了一些方法作为示例,并不是我实现的所有方法都在这里,所以这不是我编写的唯一功能。然而,所有这些评论和更多评论都是受欢迎的,因为它们可能会让我找到一个可以避免整个问题的设计。

谢谢

4

2 回答 2

0

我认为您应该研究策略模式。考虑使用可锁定性策略的组合,而不是尝试继承它。

于 2012-03-05T22:32:43.607 回答
0

如果锁定类的类型无关紧要,您可以使用装饰器模式,例如

class Lockable
{
    protected $lockable;

    public function __construct($lockable)
    {
        $this->lockable = $lockable;
    }

    public function lock()
    {
        // .. your code to lock $this->lockable
    }

    public function __call($method, $args)
    {
        return call_user_func_array(array($this->lockable, $method), $args);
    }
}

这样你就不会重复逻辑。缺点是您不能在需要修饰类型的方法中使用修饰实例(除非您添加适当的接口并委托所有调用)。

策略模式将是另一种选择:

class LockingStrategy
{
    public function lock($fileSystemObject)
    {
        // your code to lock $fileSystemObject
    }
}

class ZipFile
…
    public function __construct(LockingStrategy $strategy)
    {
        $this->lockingStrategy = $strategy;
    }
    public function lock()
    {
        $this->lockingStrategy->lock($this);
    }
}
于 2012-03-05T22:55:35.950 回答