Проблема моделирования PHP класса - PullRequest
1 голос
/ 06 марта 2012

Я написал несколько уроков и пришел на развилку в дороге по поводу того, что мне следует делать. Мой базовый вопрос: как избежать дублирования кода между классами с очень похожей функциональностью? Черты для меня сейчас не вариант, и я не думаю, что они все равно будут здесь сильно помогать.

У меня реализованы следующие классы.


    //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{}

Эти классы sortof предоставляют мне некоторые функциональные возможности типа SPLFileObject. Я могу делать следующие вещи


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


Каждый раз, когда я вызываю метод getFileSystemObject, он либо возвращает новый объект класса, либо возвращает объект, уже назначенный этому пути, что позволяет избежать создания нескольких объектов, указывающих на один и тот же путь в файловой системе. (возможно, не самая лучшая идея, но это то, что я пошел с.)

Здесь мы немного подойдем к вопросу.

У меня есть другой набор классов, которые я использую для «блокировки» объектов. Прямо сейчас единственные объекты, которые я блокирую, это filesystem_objects, независимо от того, являются ли они каталогами или файлами. Это работает достаточно просто путем создания файла блокировки для файла на основе идентификатора процесса php-процесса, пытающегося его заблокировать.



    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, но единственная причина, по которой я не хотел бы этого делать, - это то, что тогда у меня должна была бы быть часть «Locker» моей библиотеки всякий раз, когда я хочу использовать материал файловой системы; это было бы более тесно связано.

Я уверен, что у вас будут комментарии о дизайне, и некоторые скажут: «SplFileObject делает все / большую часть этого». Я включил сюда методы для примеров, и не все методы, которые я реализовал, здесь, так что это не единственная функциональность, которую я написал. Все эти комментарии и многое другое приветствуются, потому что они могут привести меня к дизайну, который позволит избежать всей этой проблемы.

Спасибо

Ответы [ 2 ]

0 голосов
/ 06 марта 2012

Если тип заблокированных классов не имеет значения, вы можете использовать шаблон Decorator, например,

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);
    }
}
0 голосов
/ 06 марта 2012

Я думаю, вы должны изучить шаблон стратегииПопробуйте использовать композицию стратегии блокируемости, а не пытаться ее наследовать.

...