Стратифицированный дизайн. Часть № 1

Стратифицированный дизайн. Часть № 1 #

Презентация #

Презентацию по теме лекции можно открыть по ссылке.

Видео-запись: Rutube

Документация #

Задания #

Задания выполняются на языке JavaScript в стиле лекции. Графы вызовов рекомендуется оформлять в mermaid или Graphviz (dot -Tsvg). Для каждого задания приводите краткое обоснование принятых решений.

  1. Построение графа вызовов. Постройте граф вызовов функции apply_discount с указанием как функций, так и использованных конструкций языка. Выделите элементы, которые находятся на более низком уровне абстракции, чем остальные, и предложите, какие из них следует скрыть за функциями.

    function apply_discount(cart, percent) {
      var copy = cart.slice();
      if (!isInCart(copy, "loyalty card"))
        return copy;
      for (var i = 0; i < copy.length; i++) {
        copy[i] = setPrice(copy[i], copy[i].price * (1 - percent / 100));
      }
      return copy;
    }
  2. Выделение слоёв по списку вызовов. Даны функции для работы с библиотекой книг и их зависимости:

    borrowBook(library, isbn)      -> isAvailable, arraySet
    returnBook(library, isbn)      -> isAvailable, arraySet
    isAvailable(library, isbn)     -> indexOfBook
    indexOfBook(library, isbn)     -> цикл for, доступ по индексу
    arraySet(array, index, value)  -> .slice(), доступ по индексу
    hasOverdueBooks(reader)        -> isOverdue, длина массива
    isOverdue(reader)              -> цикл for, доступ по индексу

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

  3. Несложная реализация. Функция has_gift смешивает уровни абстракции: она одновременно работает с бизнес-правилом и с элементами массива. Приведите её к несложной реализации: выделите функции чтения и перестройте вызовы так, чтобы has_gift оперировал только функциями одного уровня.

    function has_gift(cart) {
      var hasBook = false;
      var hasBookmark = false;
      for (var i = 0; i < cart.length; i++) {
        if (cart[i].name === "book")
          hasBook = true;
        if (cart[i].name === "bookmark")
          hasBookmark = true;
      }
      return hasBook && !hasBookmark;
    }

    Постройте графы вызовов до и после изменения и сравните количество слоёв, которые затрагивает функция.

  4. Выделение общей функции. Две функции ниже содержат одинаковый цикл поиска. Реализуйте одну из них в терминах другой, обоснуйте, какая из функций находится ниже, и постройте диаграмму вызовов, включая обращение к циклу for и индексный доступ.

    function isInLibrary(library, isbn) {
      for (var i = 0; i < library.length; i++) {
        if (library[i].isbn === isbn)
          return true;
      }
      return false;
    }
    
    function bookIndex(library, isbn) {
      for (var i = 0; i < library.length; i++) {
        if (library[i].isbn === isbn)
          return i;
      }
      return null;
    }
  5. Три уровня масштаба. Для каждого фрагмента определите, на каком уровне масштаба видна проблема: глобальном (взаимодействие между слоями), уровне слоя или уровне одной функции. Предложите исправление для найденной проблемы.

    // A
    function setQuantityByName(cart, name, quantity) {
      var index = indexOfItem(cart, name);
      if (index !== null)
        return arraySet(cart, index,
          setQuantity(cart[index], quantity));
      return cart;
    }
    
    // B
    function remove_item_by_name(cart, name) {
      var index = null;
      for (var i = 0; i < cart.length; i++) {
        if (cart[i].name === name)
          index = i;
      }
      if (index !== null)
        return removeItems(cart, index, 1);
      return cart;
    }
    
    function indexOfItem(cart, name) {
      for (var i = 0; i < cart.length; i++) {
        if (cart[i].name === name)
          return i;
      }
      return null;
    }

    В варианте A дополнительно оцените длину стрелок графа и укажите, после какого изменения длина самой длинной стрелки сократится. В варианте B поясните, почему проблему нельзя увидеть, рассматривая только одну из функций.

  6. Размещение новой функции в слоях. Для корзины уже есть функции isInCart, remove_item_by_name, add_item, calc_total, setPrice, setPriceByName и слой КПЗ-операций (arraySet, removeItems). Требуется добавить функцию remove_cheapest(cart), которая удаляет из корзины самый дешёвый товар.

    • Определите слой для новой функции и обоснуйте решение через её зависимости и назначение.
    • Постройте граф вызовов, если бы функция реализовывалась напрямую через элементы массива, и граф после применения шаблона несложной реализации.
    • Назовите, какие новые функции общего назначения потребовалось выделить и на каком слое они оказались.

© A. M. Васильев, 2026, CC BY-SA 4.0, andrey@crafted.su