Шаблоны проектирования так легко выучить!

внешний интерфейс Шаблоны проектирования
Шаблоны проектирования так легко выучить!

56.gif

Какие болевые точки призваны решить шаблоны проектирования?

Это серия подпрограмм для решения конкретных задач, обобщение опыта разработки кода предшественников, она универсальна и может использоваться многократно. его цель состоит в том, чтобы提高代码的可复用性、可读性、可维护性.
Суть шаблона проектирования заключается в практическом применении принципов объектно-ориентированного проектирования, а также в полном понимании инкапсуляции, наследования и полиморфизма классов, а также отношений ассоциации и композиции классов.
不要重复造轮子.

Что такое объектно-ориентированное программирование

  • 面向对象编程Парадигма программирования или стиль программирования. Он берет классы или объекты в качестве базовой единицы для организации кода и использует четыре характеристики инкапсуляции, абстракции, наследования и полиморфизма в качестве краеугольного камня проектирования и реализации кода.
  • 面向对象编程语言Это язык программирования, который поддерживает синтаксический механизм классов или объектов и имеет готовый синтаксический механизм, который может легко реализовать четыре характеристики объектно-ориентированного программирования.
  • 面向对象开发В том числе объектно-ориентированный анализ ООП, объектно-ориентированное проектирование ООД, объектно-ориентированное программирование ООП.

10 принципов дизайна

1. Принцип единой ответственности SRP

实现类要职责单一: Если блок кода (модуль функционального класса) отвечает за несколько функций, то изменение кода при изменении требований функции A может вызвать проблемы с функцией B, поэтому блок кода должен отвечать только за одну ответственность.

2. OCP по принципу «открыто-закрыто»

要对扩展开放,对修改关闭: Реализация новых функций путем модификации старого кода может привести к ошибкам в старых модулях, поэтому мы должны реализовывать новые функции, разрабатывая новые блоки кода.

3. Принцип подстановки Лисков LSP

不要破坏继承体系: подклассы в программе должны иметь возможность заменять родительский класс везде, где он встречается, и оставаться в соответствии с ожиданиями. Таким образом, подкласс старается не изменять ожидаемое поведение метода суперкласса.

4. Принцип изоляции интерфейса ISP

设计接口的时候要精简单一: Когда класс A является только частично требуемым интерфейсным методом B, поскольку весь его способ внедрения интерфейса необходимо реализовать, что вызывает, что вызывает несколько сегментов кода, не нужно. В этом случае интерфейс должен быть разделен B, класс нужный и нежелательный способ изолировать.

5. Принцип инверсии зависимостей DIP

面向接口编程: Абстракция не должна зависеть от деталей, детали должны зависеть от абстракции. Ядром является интерфейсно-ориентированное программирование, и мы должны полагаться на абстрактные интерфейсы, а не на конкретные классы реализации интерфейса или конкретные объекты.

Примечание. SOLID выше также известен как 5 принципов дизайна.

6. Принцип наименьшего знания (принцип Деметры) LOD

降低耦合度: класс или объект должны иметь минимальные знания о других объектах. Общайтесь только с ближайшими друзьями (сцепление).

7. Принцип комбинационного/агрегационного мультиплексирования CRP

多用组合少用继承: Всегда, когда это возможно, реализуйте новые функциональные возможности путем составления существующих объектов (заимствуя их возможности), а не используя наследование для приобретения этих возможностей.

8. Не повторяйтесь СУХО

Функциональное семантическое дублирование должно быть объединено, дублирование выполнения кода должно быть сокращено,代码逻辑重复但语义不同应该保留.

9. ДЕРЖИТЕ ЭТО ПРОСТО, ПОЦЕЛУЙТЕ

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

10. Не переусердствуйте с логикой, которая вам временно не нужна YAGNI

Не переоптимизируйте, не оставляйте слишком много точек расширения и не создавайте код, который ваши коллеги не смогут понять.

Как оценить качество кода?

  • Читаемость, масштабируемость, ремонтопригодность, возможность повторного использования, тестируемость...
  • Высокая сплоченность и низкая связанность.
  • 善战者无赫赫之功善医者无煌煌之名,大智若愚大巧若拙,真正的好代码并不是用了多少厉害的技术与奇技淫巧,而是看尽人世繁华后的返璞归真,寥寥几笔实现了功能的同时却没有任何个人风格的痕迹,符合代码规范、编程思想、设计模式的代码。

Как сформировать долговременную память?

  • 想办法把零散的知识点串联起来记忆
    • Память пирамидальной структуры формируется сверху вниз.
    • Составьте ключевые фразы для запоминания.
  • 得意忘形
    • Извлеките суть знаний, чтобы укрепить память, удалите грубое и извлеките суть.
  • 学而不思则罔,思而不学则殆
    • Глубокое мышление действительно может преобразовать знания других в свои собственные.
  • 学而时习之,不亦说乎
    • Первое обучение — это всего лишь кратковременная память в уме,需要多次复习强化才能形成长期记忆。

Меры предосторожности

Знания мертвы, а код жив. Не используйте застывшие шаблоны проектирования для реализации запрограммированной бизнес-логики.
Наша цель обучения состоит в том, чтобы иметь возможность применять то, что мы узнали, но если код, написанный другими людьми в той же группе, не может быть понят, это повлияет на удобство сопровождения и эффективность разработки проекта. Так что мы можем использовать его экономно, но мы должны овладеть его мышлением.
Твердо усвойте режим дизайна, берите интервью, берите интервью у других в группе, чтобы поделиться или может отпугнуть стаю.

23 шаблона проектирования.

  • В сокращении: 5, 7, 11, 23 — все нечетные числа.
    • 5 видов творчества
    • 7 типов структур
    • 11 типов поведения
  • Тип создания:抽工单建原型
    • Абстрактная фабрика, фабрика, один случай, строитель, прототип
  • Структурный тип:桥代理装饰适配器,享元组合成门面
    • мост, прокси, декоратор, переходник, привес, композиция, фасад (фасад)
  • Поведенческий тип:观察模板迭代的状态,命令中介解释职责链,访问策略备忘录
    • Наблюдатель, Шаблон, Итерация, Состояние, Команда, Посредник, Интерпретатор, Цепочка ответственности, Посетитель, Политика, Памятка

Создание шаблонов проектирования

封装对象创建过程,将对象的创建和使用解耦

одноэлементный шаблон

Сценарии применения

Обрабатывает нарушения доступа к ресурсам и используется для создания глобально уникальных классов.

решение

  • Ленивый: создавайте его, когда вам это нужно (сценарий: не обязательно нужен, дорого создавать, ленивая загрузка, нужно быстро запустить систему).
  • Голодный китайский стиль: создается при запуске системы (сценарий: необходимо использовать, временное создание влияет на скорость отклика).
  • Несколько экземпляров: Фиксированное количество одинаковых экземпляров одного и того же класса.

Заводская выкройка

Сценарии применения

используется для создания继承同一父类、实现同一接口的子类Объект, который создает конкретный объект с заданными параметрами типа.

решение

enum HelloType {
  A,
  B
}

interface Hello {
  sayHello()
}

class A implements Hello {
  sayHello() {
    console.log('A');
  }
}

class B implements Hello {
  sayHello() {
    console.log('B');
  }
}

class HelloFactory {
  static list = new Map<HelloType, Hello>([
    [HelloType.A, new A()],
    [HelloType.B, new B()]
  ])

  static getHello(type: HelloType) {
    return HelloFactory.list.get(type)
  }
}

// test
HelloFactory.getHello(HelloType.A).sayHello()
HelloFactory.getHello(HelloType.B).sayHello()

Абстрактный заводской узор

Сценарии применения

继承同一父类、实现同一接口的子类Object, который создает конкретный объект из заданных нескольких параметров типа.

решение

enum Type {
  A,
  B
}

enum Occupation {
  TEACHER,
  STUDENT
}

interface Hello {
  sayHello()
}

class TA implements Hello {
  sayHello() {
    console.log('Teacher A say hello')
  }
}

class TB implements Hello {
  sayHello() {
    console.log('Teacher B say hello')
  }
}

class SA implements Hello {
  sayHello() {
    console.log('Student A say hello')
  }
}

class SB implements Hello {
  sayHello() {
    console.log('Student B say hello')
  }
}

class AFactory {
  static list = new Map<Occupation, Hello>([
    [Occupation.TEACHER, new TA()],
    [Occupation.STUDENT, new SA()]
  ])

  static getHello(occupation: Occupation) {
    return AFactory.list.get(occupation)
  }
}

class BFactory {
  static list = new Map<Occupation, Hello>([
    [Occupation.TEACHER, new TB()],
    [Occupation.STUDENT, new SB()]
  ])

  static getHello(occupation: Occupation) {
    return BFactory.list.get(occupation)
  }
}

class HelloFactory {
  static list = new Map<Type, AFactory | BFactory>([
    [Type.A, AFactory],
    [Type.B, BFactory]
  ])

  static getType(type: Type) {
    return HelloFactory.list.get(type)
  }
}

// test
HelloFactory.getType(Type.A).getHello(Occupation.TEACHER).sayHello()
HelloFactory.getType(Type.A).getHello(Occupation.STUDENT).sayHello()
HelloFactory.getType(Type.B).getHello(Occupation.TEACHER).sayHello()
HelloFactory.getType(Type.B).getHello(Occupation.STUDENT).sayHello()

режим строителя

Сценарии применения

  • Есть много обязательных параметров, которые необходимо проверить при создании.
  • Во время создания оценка параметров является последовательной и взаимозависимой.
  • Существует много шагов для создания, все из которых являются успешными для создания объекта.

решение

class Programmer {
  age: number
  username: string
  color: string
  area: string

  constructor(p) {
    this.age = p.age
    this.username = p.username
    this.color = p.color
    this.area = p.area
  }

  toString() {
    console.log(this)
  }
}

class Builder {
  age: number
  username: string
  color: string
  area: string

  build() {
    if (this.age && this.username && this.color && this.area) {
      return new Programmer(this)
    } else {
      throw new Error('缺少信息')
    }
  }

  setAge(age: number) {
    if (age > 18 && age < 36) {
      this.age = age
      return this
    } else {
      throw new Error('年龄不合适')
    }
  }

  setUsername(username: string) {
    if (username !== '小明') {
      this.username = username
      return this
    } else {
      throw new Error('小明不合适')
    }
  }

  setColor(color: string) {
    if (color !== 'yellow') {
      this.color = color
      return this
    } else {
      throw new Error('yellow不合适')
    }
  }

  setArea(area: string) {
    this.area = area
    return this
  }
}

// test
const p = new Builder()
  .setAge(20)
  .setUsername('小红')
  .setColor('red')
  .setArea('hz')
  .build()
  .toString()

режим прототипа

Сценарии применения

  • Шаблон прототипа клонирует данные на основе существующего объекта, а не изменяет цепочку прототипов!
  • Стоимость создания объекта слишком высока, а значения атрибутов разных объектов-экземпляров одного типа в основном одинаковы. Экономьте ресурсы, клонируя прототипы.
  • Неизменяемые объекты реализуются поверхностным клонированием.
  • Изменяемые объекты реализуются посредством глубокого клонирования, которое требует много ресурсов.
  • Различные версии одного и того же объекта в разное время могут сравнить неизмененный поверхностный клон и измененный глубокий клон, а затем заменить старую версию новой версией.

Шаблоны структурного проектирования

总结了一些类或对象组合在一起的经典结构,这些经典结构可以解决特定应用场景的问题,将类或对象的结构和使用解耦

режим моста

Сценарии применения

  • Разделите абстракцию и реализацию, чтобы они могли меняться независимо.
  • Класс имеет несколько измерений, которые изменяются независимо друг от друга, и мы позволяем независимо расширять несколько измерений путем их объединения.
  • Очень похоже на принцип композиции по наследованию.

решение

enum MsgLevel {
  ERROR,
  WARN,
}

enum MsgType {
  EMAIL,
  PHONE
}

interface MsgContent {
  content()
}

class ErrorMsg implements MsgContent {
  content() {
    return 'ERROR'
  }
}

class WarnMsg implements MsgContent {
  content() {
    return 'WARN'
  }
}

interface MsgSender {
  send()
}

class PhoneSend implements MsgSender {
  msgContent: MsgContent

  constructor(msgContent: MsgContent) {
    this.msgContent = msgContent
  }

  send() {
    console.log(`phone send ${this.msgContent.content()}`)
  }
}

class EmailSend implements MsgSender {
  msgContent: MsgContent

  constructor(msgContent: MsgContent) {
    this.msgContent = msgContent
  }

  send() {
    console.log(`email send ${this.msgContent.content()}`)
  }
}

// test 此处还可以做成map结构继续优化(略)
new PhoneSend(new WarnMsg()).send()
new PhoneSend(new ErrorMsg()).send()
new EmailSend(new WarnMsg()).send()
new EmailSend(new ErrorMsg()).send()

прокси-режим

Сценарии применения

  • Добавьте нефункциональные требования к исходному классу, чтобы отделить код от исходного бизнеса.
  • Разработка нефункциональных требований к бизнес-системам: мониторинг, статистика, аутентификация, ограничение тока, логирование, кеширование.

решение

  • Реализовано через наследование (не рекомендуется)
class User{
  login(){
    console.log('user login...')
  }
}

class UserProxy extends User{
  login() {
    console.log('login before')
    super.login()
    console.log('login after')
  }
}
  • Реализовано через интерфейс (рекомендуется)
interface Login {
  login()
}

class User implements Login {
  login() {
    console.log('user login...')
  }
}

class UserProxy implements Login {
  user = new User()

  login() {
    console.log('login before')
    this.user.login()
    console.log('login after')
  }
}

Шаблон декоратора

Сценарии применения

  • Класс декоратора - это улучшение оригинальной функции.
  • Класс декоратора наследует тот же родительский класс, что и исходный класс, поэтому мы можем вкладывать несколько классов декоратора в исходный класс.
  • В основном это решает проблему, заключающуюся в том, что отношения наследования слишком сложны, и заменяет наследование через композицию.
  • Можно использовать несколько декораторов, вложив исходный класс.

решение

  • Реализовано с помощью АОП
Function.prototype.before = function (beforeFn) {
  return (...arg) => {
    beforeFn(...arg);
    return this(...arg);
  }
};
Function.prototype.after = function (afterFn) {
  return (...arg) => {
    const result = this(...arg);
    afterFn(...arg);
    return result;
  }
};

function ImportEvent1 {
  console.log('重要的事情说三遍 1')
}

function ImportEvent2 {
  console.log('重要的事情说三遍 2')
}

function ImportEvent3 {
  console.log('重要的事情说三遍 3')
}

// test
ImportEvent2.before(ImportEvent1).after(ImportEvent3)()

режим адаптера

Сценарии применения

  • Шаблон адаптера используется для устранения недостатков дизайна и обеспечения совместимости несовместимых интерфейсов.
  • Инкапсулируйте ошибочный дизайн интерфейса.
  • Унифицируйте дизайн интерфейса нескольких классов.
  • Замените зависимые внешние системы.
  • Совместим со старыми версиями интерфейса.
  • Адаптируйтесь к данным в разных форматах.

решение

  • В исходном интерфейсе не так много методов, можно использовать как адаптеры классов, так и адаптеры объектов.
  • Если исходный класс имеет много методов и разница с целевым интерфейсом невелика, используйте адаптер класса, чтобы уменьшить объем кода.
  • Если в исходном классе много методов и разница с целевым интерфейсом велика, используйте объектный адаптер, а композиция лучше, чем наследование.
// 目标接口格式
interface ITarget {
  f1()

  f2()

  f3()
}

// 原有类与目标接口不兼容
class Origin {
  fa() {
  }

  fb() {
  }

  f3() {
  }
}

// 使用适配器来兼容
class Adaptor implements ITarget {
  origin = new Origin()

  f1() {
    this.origin.fa()
  }

  f2() {
    this.origin.fb()
  }

  f3() {
    this.origin.f3()
  }
}

наилегчайший образец

Сценарии применения

  • общий блок. Повторное использование объектов для экономии памяти при условии, что объект-легковес является неизменяемым объектом (он не изменится после инициализации).

решение

  • Например, в онлайн-шахматной игре 1000 комнат, в каждой комнате есть шахматная доска, текущее состояние шахматной доски (положение фигур) разное, но размер, цвет и название фигур одинаковые и фиксированные, и может быть спроектирован как Flyweight.

Комбинированный режим

Сценарии применения

Организуйте набор объектов в древовидную структуру, чтобы представить иерархию часть-целое. Режим композиции позволяет клиентам унифицировать логику обработки (рекурсивный обход) отдельных объектов и составных объектов.

решение

abstract class FileSystemNode {
  path: string

  abstract getFilesCount()

  abstract getFilesSize()
}

class FileNode extends FileSystemNode {
  constructor(path) {
    super();
    this.path = path
  }

  getFilesCount() {
    return 1
  }

  getFilesSize() {
    return require(this.path).length
  }
}

class Directory extends FileSystemNode {
  subNodes = []

  constructor(path) {
    super();
    this.path = path
  }

  getFilesCount() {
    return this.subNodes.reduce(item => item.getCount(), 0)
  }

  getFilesSize() {
    return this.subNodes.reduce(item => item.getSize(), 0)
  }
}

Режим фасада (внешнего вида)

Сценарии применения

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

Шаблоны поведенческого проектирования

总结了一些类或对象交互的经典方式,将该行为相关的类或对象解耦

Шаблон наблюдателя

Сценарии применения

  • Отделите наблюдателя от наблюдаемого.
  • В режиме публикации-подписки есть центр планирования публикации-подписки (посредник), а в режиме наблюдателя его нет!

решение

// 目标对象
class Subject {
  observerList: Observer[]

  constructor() {
    this.observerList = [];
  }

  addObserver(observer) {
    this.observerList.push(observer);
  }

  notify() {
    this.observerList.forEach((observer) => {
      observer.update();
    });
  }
}

// 观察者
class Observer {
  cb: Function

  constructor(cb: Function) {
    if (typeof cb === "function") {
      this.cb = cb;
    } else {
      throw new Error("Observer构造器必须传入函数类型!");
    }
  }

  update() {
    this.cb();
  }
}


// test
const observerCallback = function () {
  console.log("我被通知了");
};
const observer = new Observer(observerCallback);
const subject = new Subject();
subject.addObserver(observer);
subject.notify();

Режим шаблона

Сценарии применения

  • Определите скелет алгоритма (бизнес-логики) в методе и отложите определенные шаги до подклассов. Шаблон Template Method позволяет подклассам переопределять определенные шаги в алгоритме без изменения общей структуры алгоритма.
  • Повторное использование расширения.

решение

abstract class Drinks {
  firstStep() {
    console.log('烧开水')
  }

  abstract secondStep()

  thirdStep() {
    console.log('倒入杯子')
  }

  abstract fourthStep()

  drink() {
    this.firstStep()
    this.secondStep()
    this.thirdStep()
    this.fourthStep()
  }
}

class Tea extends Drinks {
  secondStep() {
    console.log('浸泡茶叶')
  }

  fourthStep() {
    console.log('加柠檬')
  }
}

class Coffee extends Drinks {
  secondStep() {
    console.log('冲泡咖啡')
  }

  fourthStep() {
    console.log('加糖')
  }
}

// test
const tea = new Tea()
tea.drink()
const coffee = new Coffee()
coffee.drink()

режим стратегии

Сценарии применения

  • Определите семейство алгоритмов, инкапсулируйте каждый алгоритм отдельно и сделайте их взаимозаменяемыми.
  • Избегайте многословных операторов if-else или переключений.

решение

enum StrategyType {
  S,
  A,
  B
}

const strategyFn = {
  'S': function (salary: number) {
    return salary * 4
  },
  'A': function (salary: number) {
    return salary * 3
  },
  'B': function (salary: number) {
    return salary * 2
  }
}

const calculateBonus = function (level: StrategyType, salary: number) {
  return strategyFn[level](salary)
}

calculateBonus(StrategyType.A, 10000) // 30000

Схема цепочки ответственности

Сценарии применения

  • Несколько процессоров ABC обрабатывают один и тот же запрос по очереди, чтобы сформировать цепочку Когда процессор может обработать запрос, он не будет передаваться последующим процессорам.
  • Процессор-перехватчик фильтров.

решение

const order500 = function (orderType, pay, stock) {
  if (orderType === 1 && pay === true) {
    console.log("500 元定金预购, 得到 100 元优惠券");
    return true;
  } else {
    return false;
  }
};

const order200 = function (orderType, pay, stock) {
  if (orderType === 2 && pay === true) {
    console.log("200 元定金预购, 得到 50 元优惠券");
    return true;
  } else {
    return false;
  }
};

const orderCommon = function (orderType, pay, stock) {
  if ((orderType === 3 || !pay) && stock > 0) {
    console.log("普通购买, 无优惠券");
    return true;
  } else {
    console.log("库存不够, 无法购买");
    return false;
  }
};

class chain {
  fn: Function
  nextFn: Function

  constructor(fn: Function) {
    this.fn = fn;
    this.nextFn = null;
  }

  setNext(nextFn) {
    this.nextFn = nextFn
  }

  init(...arguments) {
    const result = this.fn(...arguments);
    if (!result && this.nextFn) {
      this.nextFn.init(...arguments);
    }
  }
}

const order500New = new chain(order500);
const order200New = new chain(order200);
const orderCommonNew = new chain(orderCommon);

order500New.setNext(order200New);
order200New.setNext(orderCommonNew);

order500New.init(3, true, 500); // 普通购买, 无优惠券

режим состояния

Сценарии применения

  • Каждое состояние внутри объекта инкапсулировано в класс, и изменения во внутреннем состоянии приводят к различному поведению.

решение

class weakLight {
  light: Light

  constructor(light: Light) {
    this.light = light
  }

  press() {
    console.log('打开强光')
    this.light.setState(this.light.strongLight)
  }
}

class strongLight {
  light: Light

  constructor(light: Light) {
    this.light = light
  }

  press() {
    console.log('关灯')
    this.light.setState(this.light.offLight)
  }
}

class offLight {
  light: Light

  constructor(light: Light) {
    this.light = light
  }

  press() {
    console.log('打开弱光')
    this.light.setState(this.light.weakLight)
  }
}


class Light {
  weakLight: weakLight
  strongLight: strongLight
  offLight: offLight
  currentState: offLight | weakLight | strongLight //当前状态: 默认关灯状态

  constructor() {
    this.weakLight = new weakLight(this)
    this.strongLight = new strongLight(this)
    this.offLight = new offLight(this)
    this.currentState = this.offLight
  }

  press() {
    this.currentState.press()
  }

  setState(state) {
    this.currentState = state
  }
}

// test
const light = new Light()
light.press()
light.press()
light.press()
light.press()
light.press()
light.press()

шаблон итератора

Сценарии применения

  • Итерация по объектам коллекции.

шаблон посетителя

Сценарии применения

  • Позволяет применять одну или несколько операций к набору объектов, отделяя операции от самих объектов.

режим заметки

Сценарии применения

  • Не нарушая принципа инкапсуляции, захватывать внутреннее состояние объекта и сохранять это состояние вне объекта, чтобы впоследствии объект можно было восстановить в прежнее состояние.

решение

class Programmer {
  age: number
  username: string
  color: string
  area: string

  constructor(p) {
    this.age = p.age
    this.username = p.username
    this.color = p.color
    this.area = p.area
  }

  // 创建一个快照
  createSnapshot() {
    return {
      age: this.age,
      username: this.username,
      color: this.color,
      area: this.area
    }
  }

  // 通过快照恢复对象状态
  restoreSnapshot(snapshot: Programmer) {
    this.age = snapshot.age
    this.username = snapshot.username
    this.color = snapshot.color
    this.area = snapshot.area
  }
}

командный режим

Сценарии применения

  • Основная функция и сценарий применения командного режима — управление выполнением команд, таких как асинхронные, отложенные, очереди, команды отмены и повтора, команды сохранения и команды регистрации. Разделите инициатора и исполнителя команды.

решение

interface Command {
  execute()
}

class closeDoorCommand implements Command {
  execute() {
    console.log('close door');
  }
}

class openPcCommand implements Command {
  execute() {
    console.log('open pc');
  }
}

class openQQCommand implements Command {
  execute() {
    console.log('login qq');
  }
}

class CommandManager {
  commandList: Command[] = []

  addCommand(command: Command) {
    this.commandList.push(command)
  }

  execute() {
    this.commandList.forEach(command => {
      command.execute()
    })
  }
}

//test
const commandManager = new CommandManager();
commandManager.addCommand(new closeDoorCommand());
commandManager.addCommand(new openPcCommand());
commandManager.addCommand(new openQQCommand());
commandManager.execute();

Режим переводчика

Сценарии применения

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

модель посредничества

Сценарии применения

  • Идея дизайна шаблона посредничества очень похожа на идею среднего уровня.Путем введения среднего уровня посредничества отношение взаимодействия (отношение зависимости) между группой объектов преобразуется в отношение «один ко многим» ( звездные отношения). Первоначально объект должен взаимодействовать с n объектами, но теперь ему нужно взаимодействовать только с одним промежуточным объектом, что сводит к минимуму взаимодействие между объектами, снижает сложность кода и улучшает читаемость и удобство сопровождения кода.

别忘记对我素质三连,点赞、关注、评论
求点赞.jpg