2015-02-14 6 views
2

У меня довольно большой класс XYZ, который отличается поведением с разными аргументами. Каждый аргумент должен иметь helptext.Инкапсулировать функциональные возможности в классы

Поскольку класс XYZ очень большой, я хочу, чтобы инкапсулировать все функции аргументов в argumentManager класса, и все связанные функции помогают в helpManager класса. Это возможно, поскольку они имеют функции, не зависящие от XYZ. Результат таков:

<?php 

class ArgumentManager { 

    // DO NOT CALL 
    public function addArgument($option, $argumentCount) { 
     ... 
    } 

    // Other functions MAY be called by the user 
    public function isArgumentInList($option) { 
     ... 
    } 

    ... 

} 

class HelpManager { 

    // DO NOT CALL 
    public function addHelpEntry($option, $helptext) { 
     ... 
    } 

    // Other functions MAY be called by the user 
    public function printHelpPage() { 
     ... 
    } 

    ... 

} 

class XYZ { 

    private $helpManager; 
    private $argumentManager; 

    // The user may call everything in there, EXCEPT HelpManager::addHelpEntry, since it must be a created pair by XYZ::addArgumentWithHelp 
    public function getHelpManager() { 
     return $this->helpManager; 
    } 

    // The user may call everything in there, EXCEPT ArgumentManager::addArgument, since it must be a created pair by XYZ::addArgumentWithHelp 
    public function getArgumentManager() { 
     return $this->argumentManager; 
    } 

    // Create classes which contain independent functionalities 
    public function __construct() { 
     $this->helpManager = new HelpManager(); 
     $this->argumentManager = new ArgumentManager(); 
    } 

    // Intended usage for creating an argument with help (they should always be a couple) 
    public function addArgumentWithHelp($option, $helptext, $argumentCount) { 
     $this->argumentManager->addArgument($option, $argumentCount); 
     $this->helpManager->addHelpEntry($option, $helptext); 
    } 

    // Many other functions of the big class XYZ 
    ..... 

} 

Класс XYZ теперь гораздо меньше.

Аргумент с helptext может быть добавлен путем вызова $XYZ->addArgumentWithHelp().

Функции, связанные с соответствующими функциями, могут быть вызваны, например, через $XYZ->getHelpManager()->printHelpPage(). То же самое относится к связанным с Аргументом функциям.

Проблема заключается в том, что я не хочу, чтобы $XYZ->getHelpManager()->addHelpEntry() или $XYZ->getArgumentManager->addArgument() называют кем-то другим, кроме XYZ, так как я хочу, чтобы обеспечить соблюдение, что обоих, argumentManager и helpManager имеют информацию о опции.

+1

Немного неясно, для чего вы хотите, чтобы результат был. Вы утверждаете, что хотите ограничить вызов аргументаManager/helpManager XYZ или что вы хотите скрыть аргументManager/helpManager извне класса, но все же разрешить метод addArgument? Или что-то другое? – kellanburket

+0

Функции внутри $ argumentManager и $ helpManager могут быть вызваны, чтобы пользователь мог работать с ними. Единственными функциями, которые не следует вызывать, являются те, которые я обозначил как «НЕ ЗВОНО». Они должны быть вызваны только классом XYZ. В других языках программирования, таких как Delphi, я бы установил видимость только «unit only» (unit = script file) –

ответ

0

Так что вам нужно сделать свойство private или protected поэтому они доступны только через XYZ:

class XYZ 
{ 
    protected $helpManager; 
    protected $argumentManager; 

    public function __construct(ArgumentManager $argumentManager, HelpManager $helpManager) { 
     $this->helpManager = $helpManager; 
     $this->argumentManager = $argumentManager 
    } 

    // CORRECT USAGE 
    public function addArgument($option, $helptext) { 
     $this->argumentManager->addArgument($option, $argumentCount); 
     $this->helpManager->addHelpEntry($option, $helptext); 

     return $this; 

    } 

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

+0

Имея $ helpManager и $ argumentManager protected, он не решает проблему. Пользователь должен вызывать функции внутри этих экземпляров, например. '$ XYZ-> helpManager-> printHelpPage()'.Единственными функциями, которые не следует вызывать, являются те, которые я обозначил как «НЕ ЗВОНО». Они должны быть вызваны только классом XYZ. В других языках программирования, таких как Delphi, я бы установил видимость на «unit only» (unit = script file) –

0

Это звучит так, как будто вы говорите о дружбе стиля C++, в которой определенные классы имеют привилегированный доступ к закрытым и защищенным членам так называемого класса друзей. К сожалению, дружба не реализована в PHP. Если вы ищете сложное обходное решение с использованием пространств имен для изменения видимости, вы можете прочитать это сообщение: Nested Or Inner Classes in PHP

0

Что вы хотите, это можно сделать с помощью свойств.

Объявите основные части диспетчера аргументов и менеджера справки как черты с функциями, которые вы не хотите вызывать извне как защищенные.

Объявляйте реальные классы диспетчера аргументов и помощников менеджеров, используя эти черты.

Внутри XYZ объявляются варианты реальных классов диспетчера аргументов и справочных менеджеров, но переопределяют видимость защищенных функций как общедоступных. Затем изнутри XYZ вы можете набирать cast из реального класса в класс вариантов и вызывать методы, необходимые для вызова внутренних копий.

Извините за отсутствие примеров кода, я печатаю это на своем планшете. Если вы хотите, я могу предоставить их позже, но между тем прочитайте раздел руководства по параметрам php.

+0

Спасибо за эту информацию! Извините, но я не совсем понимаю. Это исходный сценарий (очень простой для демонстрации): http://pastebin.com/NugSQFUj. Я пробовал это так, но я как-то делаю это неправильно: http://pastebin.com/K1KJq2yJ –

+0

Я дам вам пару альтернативных ответов, используя черты, вы можете выбрать один на досуге. – delatbabel

+0

Обратите внимание, что в вашем втором pastebin код, который вы даете, не будет работать. На этом этапе: ** $ test = (HelpManagerTrait) $ test; ** вы пытаетесь привить объект к признаку, который не может быть выполнен. Прочтите раздел руководства в деталях чуть подробнее: http://php.net/manual/en/language.oop5.traits.php – delatbabel

0

Я думаю, что нашел решение/обходное решение. Используя отражение, я принудительно вызываю addArgument, изменяя видимость во время выполнения, что произойдет только в классе XYZ. Пользователь не может случайно получить доступ к этим защищенным методам.

<?php 

class ArgumentManager { 

    // Will be called by "friend" class XYZ 
    protected function addArgument($option, $argumentCount) { 
     ... 
    } 

    // Other functions MAY be called by the user 
    public function isArgumentInList($option) { 
     ... 
    } 

    ... 

} 

class HelpManager { 

    // Will be called by "friend" class XYZ 
    protected function addHelpEntry($option, $helptext) { 
     ... 
    } 

    // Other functions MAY be called by the user 
    public function printHelpPage() { 
     ... 
    } 

    ... 

} 

class XYZ { 

    private $helpManager; 
    private $argumentManager; 

    public function getHelpManager() { 
     return $this->helpManager; 
    } 

    public function getArgumentManager() { 
     return $this->argumentManager; 
    } 

    // Create classes which contain independent functionalities 
    public function __construct() { 
     $this->helpManager = new HelpManager(); 
     $this->argumentManager = new ArgumentManager(); 
    } 

    // Intended usage for creating an argument with help (they should always be a couple) 
    public function addArgumentWithHelp($option, $helptext, $argumentCount) { 
     $argMethod = new ReflectionMethod($this->argumentManager, 'addArgument'); 
     $argMethod->setAccessible(true); 
     $argMethod->invoke($this->argumentManager, $option, $argumentCount); 

     $helpMethod = new ReflectionMethod($this->helpManager, 'addHelpEntry'); 
     $helpMethod->setAccessible(true); 
     $helpMethod->invoke($this->helpManager, $option, $helptext); 
    } 

    // Many other functions of the big class XYZ 
    ..... 

} 
1

В ваш первоначальный вопрос вы спросили:

Поскольку класс XYZ очень большой, я хочу, чтобы инкапсулировать все-аргумента функции в классе argumentManager, и все помогают функции, связанные в классе helpManager ,

Похоже, что то, что вам действительно нужно достичь, можно сделать, используя черты без каких-либо дополнительных классов вообще. Вот как я бы структурировать его, не включая весь код (который вы можете вырезать и вставить из оригинального вопроса):

<?php 

trait ArgumentManagerTrait { 

    // DO NOT CALL 
    protected function addArgument($option, $argumentCount) { 
     ... 
    } 

    // Other functions MAY be called by the user 
    public function isArgumentInList($option) { 
     ... 
    } 

    ... 

} 

trait HelpManagerTrait { 

    // DO NOT CALL 
    protected function addHelpEntry($option, $helptext) { 
     ... 
    } 

    // Other functions MAY be called by the user 
    public function printHelpPage() { 
     ... 
    } 

    ... 

} 

class XYZ { 

    use HelpManagerTrait, ArgumentManagerTrait; 

    // Intended usage for creating an argument with help (they should always be a couple) 
    public function addArgumentWithHelp($option, $helptext, $argumentCount) { 
     $this->addArgument($option, $argumentCount); 
     $this->addHelpEntry($option, $helptext); 
    } 

    // Many other functions of the big class XYZ 
    ..... 

} 

В этом решении вы делаете от необходимости каких-либо дополнительных классов или внутренних объектов и просто инкапсулировать все, используя черты. Это чище и опрятно, и это решение, которое я бы выбрал. Поскольку HelpManagerTrait и ArgumentManagerTrait являются чертами родительского класса, тогда их методы (защищенные и общедоступные) становятся частью родителя.

0

Вот еще один ответ, для которого я должен быть немного философским. Вы можете объявлять классы и черты, как это:

<?php 

trait ArgumentManagerTrait { 

    // DO NOT CALL 
    protected function addArgument($option, $argumentCount) { 
     ... 
    } 

    // Other functions MAY be called by the user 
    public function isArgumentInList($option) { 
     ... 
    } 

    ... 

} 

trait HelpManagerTrait { 

    // DO NOT CALL 
    protected function addHelpEntry($option, $helptext) { 
     ... 
    } 

    // Other functions MAY be called by the user 
    public function printHelpPage() { 
     ... 
    } 

    ... 

} 

class HelpManager { use HelpManagerTrait; } 
class ArgumentManager { use ArgumentManagerTrait; } 
class HelpManagerInternal { use HelpManagerTrait { addHelpEntry as public; } 
class ArgumentManagerInternal { use ArgumentManagerTrait { addArgument as public; } 

class XYZ { 

    protected $helpManager; // of class HelpManagerInternal 
    protected $argumentManager; // of class ArgumentManagerInternal 

    public function __construct(ArgumentManager $argumentManager, HelpManager $helpManager) { 
     $this->helpManager = $this->helpManagerCastToInternal($helpManager); 
     $this->argumentManager = $this->argumentManagerCastToInternal($argumentManager); 
    } 

    // Intended usage for creating an argument with help (they should always be a couple) 
    public function addArgumentWithHelp($option, $helptext, $argumentCount) { 
     $this->argumentManager->addArgument($option, $argumentCount); 
     $this->helpManager->addHelpEntry($option, $helptext); 
    } 

    public function getHelpManager() { 
     return $this->helpManagerCastToExternal($this->helpManager); 
    } 

    public function getArgumentManager() { 
     return $this->argumentManagerCastToExternal($this->argumentManager); 
    } 

    // Many other functions of the big class XYZ 
    ..... 

} 

Вы заметите, что я опустил 4 функции здесь - helpManagerCastToInternal, helpManagerCastToExternal и тот же 2 для argumentManager. Как вы их реализуете, зависит от внутренней структуры атрибутов аргументов/классов аргументаManager и helpManager, которые вы не указали в своем вопросе.

Что бы я хотел сделать, так это, чтобы оба класса сходили с чего-то вроде Laravel \ Fluent или Symfony \ Component \ HttpFoundation \ ParameterBag. Это классы в рамках, которые вы можете использовать в использовании композитора, и вы можете логически использовать внутреннюю память атрибутов с помощью сеттеров/геттеров и т. Д. Затем ваша функция трансляции может просто извлекать все атрибуты одного объекта, создать новый объект другого типа, а затем перенести атрибуты из первого объекта во второй объект - castToInternal и castToExternal в основном выполнять задания друг друга, но наоборот. Обратите внимание, что это действительно объект копия, а не объект листинг, так что если ваши другие функции в helpManager и argumentManager беспорядочны с внутренними атрибутами, вам нужно скопировать их обратно в какой-то момент, что может и не быть тем, что вы хотите.

Альтернативно вы можете использовать методы отражения, как предлагается здесь: How to Cast Objects in PHP - это будет работать независимо от вашей внутренней структуры атрибутов.

Это действительно зависит от того, как вы хотите структурировать и использовать внутренние атрибуты ваших классов (отсюда и бит о том, чтобы быть философским).

Смежные вопросы