Как решить нарушения Закона Demeter?

Я думаю, что если кто-то захочет использовать PHP и MySQL или какой-нибудь другой сервер базы данных:

  1. Подумайте об обучении PDO (объекты данных PHP) - это база данных уровень доступа, обеспечивающий единый метод доступа к нескольким базам данных.
  2. Подумайте об обучении MySQLi
  3. Используйте собственные функции PHP, такие как: strip_tags , mysql_real_escape_string или если переменная числовая, просто (int)$foo. Подробнее о типах переменных в PHP читайте здесь . Если вы используете библиотеки, такие как PDO или MySQLi, всегда используйте PDO :: quote () и mysqli_real_escape_string () .

Примеры библиотек:

---- PDO

----- Никакие заполнители - не спешили для SQL-инъекций! Это плохо

$request = $pdoConnection->("INSERT INTO parents (name, addr, city) values ($name, $addr, $city)");

----- Без имени заполнители

$request = $pdoConnection->("INSERT INTO parents (name, addr, city) values (?, ?, ?);

----- Именованные заполнители

$request = $pdoConnection->("INSERT INTO parents (name, addr, city) value (:name, :addr, :city)");

--- MySQLi

$request = $mysqliConnection->prepare('
       SELECT * FROM trainers
       WHERE name = ?
       AND email = ?
       AND last_login > ?');

    $query->bind_param('first_param', 'second_param', $mail, time() - 3600);
    $query->execute();

PS:

PDO побеждает в этом сражении с легкостью. Благодаря поддержке двенадцати различных драйверов баз данных и именованных параметров мы можем игнорировать небольшую потерю производительности и привыкнуть к ее API. С точки зрения безопасности, оба они являются безопасными, пока разработчик использует их так, как они должны использоваться

. Но хотя PDO и MySQLi довольно быстры, MySQLi выполняет незначительную скорость в тестах - ~ 2,5% для незаготовленных отчетов и ~ 6,5% для подготовленных.

И, пожалуйста, проверьте каждый запрос в своей базе данных - это лучший способ предотвратить инъекцию.

36
задан DGM 21 January 2012 в 16:55
поделиться

7 ответов

Мое понимание последствий Закона Demeter, кажется, отличается от DrJokepu - каждый раз, когда я применил его к объектно-ориентированному коду, это привело к более трудной инкапсуляции и сцеплению, а не добавлению дополнительных методов get для заключения контракта путей в процессуальном кодексе.

Википедия имеет правило как [1 111]

более официально, Закон Demeter для функций требует, чтобы метод M объекта O мог только вызвать методы следующих видов объектов:

  1. сам O
  2. параметры М
  3. любые объекты создали/инстанцировали в прямых объектах O M
  4. компонента

, Если у Вас есть метод, который берет 'кухню' в качестве параметра, Demeter заявляет, что Вы не можете осмотреть компоненты кухни, не, что можно только осмотреть непосредственные компоненты.

Запись набора функций только для удовлетворения Закона Demeter как это

Kitchen.GetCeilingColour()

просто похожа на общую пустую трату времени для меня и на самом деле добирается, мой способ добиться цели

, Если метод за пределами Кухни передается кухня, строгим Demeter это не может назвать методы на результате GetCeilingColour () на нем также.

, Но так или иначе, точка должна удалить зависимость от структуры вместо того, чтобы переместить представление структуры от последовательности цепочечных методов к названию метода. Создание методов, таких как MoveTheLeftHindLegForward () в классе Собаки ничего не делает к выполнению Demeter. Вместо этого назовите dog.walk () и позвольте собаке обработать свои собственные участки.

, Например, что, если требования изменяются и мне будет нужна высота потолка также?

я осуществил бы рефакторинг код так, чтобы Вы работали с комнатой и потолками:

interface RoomVisitor {
  void visitFloor (Floor floor) ...
  void visitCeiling (Ceiling ceiling) ...
  void visitWall (Wall wall ...
}

interface Room { accept (RoomVisitor visitor) ; }

Kitchen.accept(RoomVisitor visitor) {
   visitor.visitCeiling(this.ceiling);
   ...
}

Или можно пойти далее и устранить методов get полностью путем передачи параметров потолка к visitCeiling методу, но это часто представляет хрупкую связь.

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

Однако Demeter относится к системам OO - где данные инкапсулируются в объектах, которые работают на данные - а не система, о которой Вы говорите, который имеет различные слои данные, передаваемые между слоями в немых, navigatable структурах. Я не вижу, что Demeter может обязательно быть применен к таким системам так же легко относительно монолитных или основанных на сообщении. (В основанной на сообщении системе Вы не можете перейти ни к чему, что не находится в граммах сообщения, таким образом, Вы застреваете с Demeter, нравится ли Вам это или нет)

30
ответ дан Pete Kirkham 27 November 2019 в 05:43
поделиться

Я знаю, что собираюсь получить downvoted к общей аннигиляции, но я должен сказать, что сортирую Закона о неприязни Demeter. Конечно, вещи как

dictionary["somekey"].headers[1].references[2]

действительно ужасны, но рассматривают это:

Kitchen.Ceiling.Coulour

у меня ничего нет против этого. Запись набора функций только для удовлетворения Закона Demeter как это

Kitchen.GetCeilingColour()

просто похожа на общую пустую трату времени для меня и на самом деле добирается, мой способ добиться цели. Например, что, если требования изменяются и мне будет нужна высота потолка также? С Законом Demeter я должен буду записать другую функцию в Кухне, таким образом, я могу получить Высоту потолка непосредственно, и в конце у меня будет набор крошечных функций метода get везде, который является чем-то, что я рассмотрел бы небольшим количеством путаницы.

РЕДАКТИРОВАНИЕ: Позволяют мне перефразировать свою точку:

Находится на одном уровне это абстракции вещей, столь важных, что я проведу время при записи 3-4-5 уровней методов get/методов set? Это действительно делает обслуживание легче? Конечный пользователь получает что-нибудь? Действительно ли это стоит моего времени? Я не думаю так.

21
ответ дан Tamas Czinege 27 November 2019 в 05:43
поделиться

Традиционное решение нарушений Demeter, "говорят, не спрашивайте". Другими словами, на основе Вашего состояния, необходимо сказать управляемый объект (любой объект, который Вы держите) принять некоторые меры - и это решит, сделать ли то, что Вы спрашиваете, в зависимости от его собственного состояния.

Как простой пример: мой код использует платформу журналирования, и я говорю моему регистратору, что хочу произвести сообщение отладки. Регистратор тогда решает, на основе его конфигурации (возможно, отладка не включена для него), отправить ли на самом деле сообщение на его устройства вывода. Нарушение ЛОДА в этом случае было бы для моего объекта спросить регистратор, собирается ли это сделать что-нибудь с сообщением. Путем выполнения так, я теперь связал свой код со знанием внутреннего состояния регистратора (и да, я выбрал этот пример намеренно).

Однако ключевой пункт этого примера - то, что регистратор реализует поведение .

, Где я думаю, ЛОД ломается, при контакте с объектом, который представляет данные , с никакое поведение .

, В этом случае, IMO пересекающий графа объектов не отличается, чем применение выражения XPath к DOM. И добавление методов такой как "isThisMedicationWarranted ()" является худшим подходом, потому что теперь Вы распределяете бизнес-правила среди своих объектов, делая их тяжелее для понимания.

11
ответ дан kdgregory 27 November 2019 в 05:43
поделиться

Я должен был бы предположить, что бизнес-логика, которая требует Разрешимый, требует других вещей также. Если так, может некоторая часть его быть инкапсулированной в Медицине значимым способом (более значимый, чем Medicine.isSoluble ())?

Другая возможность (вероятно, излишество и не полное решение одновременно) состояла бы в том, чтобы представить бизнес-правило, поскольку собственный объект и использование удваивают Отправку/Шаблон "посетитель":

RuleCompilator
{
  lookAt(Protocol);
  lookAt(Medicine);
  lookAt(AdminstrationProcedure) 
}

MyComplexRuleCompilator : RuleCompilator
{
  lookaAt(Protocol)
  lookAt(AdminstrationProcedure)
}

Medicine
{
  applyRuleCompilator(RuleCompilator c) {
    c.lookAt(this);
    AdministrationProtocol.applyRuleCompilator(c);
  }
}
2
ответ дан Yeldar Kurmangaliyev 27 November 2019 в 05:43
поделиться

Для BLL моя идея состояла в том, чтобы добавить свойство на Медицине как это:

public Boolean IsSoluble
{
    get { return AdministrationRoute.Soluble; } 
}

то, Которое является тем, что я думаю, описано в статьях о Законе Demeter. Но насколько это создаст помехи классу?

1
ответ дан Davy Landman 27 November 2019 в 05:43
поделиться

Относительно первого примера с "разрешимым" свойством у меня есть несколько комментариев:

  1. , Что такое "AdministrationRoute" и почему разработчик ожидал бы получать разрешимое свойство медицины от него? Эти два понятия кажутся совершенно не связанными. Это означает, что код не связывается очень хорошо и возможно разложение классов, которые Вы уже имеете, мог быть улучшен. Изменение разложения могло привести Вас видеть другие решения для своих проблем.
  2. Разрешимый не прямой член медицины по причине. Если Вы находите, что необходимо получить доступ к нему непосредственно тогда, возможно, это должен быть прямой участник. Если существует дополнительная необходимая абстракция, то возвратите ту дополнительную абстракцию из медицины (или непосредственно или по доверенности или faГ§ade). Что-либо, чему нужно разрешимое свойство, может работать над абстракцией, и Вы могли использовать ту же абстракцию для нескольких дополнительных типов, таких как подложки или витамины.
1
ответ дан Joris Timmermans 27 November 2019 в 05:43
поделиться

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

, Например, в C++:

class Medicine {
public:
    AdministrationRoute()& getAdministrationRoute() const { return _adminRoute; }

private:
    AdministrationRoute _adminRoute;
};

Тогда

if (Medicine.AdministrationRoute.Soluble) ...

становится

if (Medicine.getAdministrationRoute().Soluble) ...

, Это дает Вам гибкость, чтобы изменить getAdministrationRoute () в будущем к, например, выбрать AdministrationRoute от Таблицы базы данных по требованию.

1
ответ дан j_random_hacker 27 November 2019 в 05:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: