1. Что такое структурный паттерн
Структурные паттерны в основном используются для работы с комбинацией классов и объектов, соответствующих интеллект-картам:
2. Режим внешнего вида:Facade Pattern
Скройте сложность вторичной инкапсуляции интерфейса и упростите его использование. Режим внешнего вида включает в себя следующие роли:
-
Facade
: Внешний вид роль -
SubSystem
: Роль подсистемы
Когда мы разделяем систему на несколько подсистем, мы уменьшаем сложность кода. При программировании рекомендуется свести к минимуму взаимодействие и зависимости между подсистемами. Хорошим способом добиться этого является введениеfacade
Объекты, обеспечивающие единый и унифицированный интерфейс для подсистем.
1. Следите за событиями в разных браузерах
Чтобы убедиться, что код, обрабатывающий событие, работает последовательно в большинстве браузеров, вам нужно обратить внимание на фазу всплытия.
При создании кроссбраузерного веб-сайтаВы непреднамеренно использовали режим внешнего вида:
var addMyEvent = function( el,ev,fn ){
if( el.addEventListener ){//存在DOM2级方法,则使用并传入事件类型、事件处理程序函数和第3个参数false(表示冒泡阶段)
el.addEventListener( ev,fn, false );
}else if(el.attachEvent){ // 为兼容IE8及更早浏览器,注意事件类型必须加上"on"前缀
el.attachEvent( "on" + ev, fn );
}else{
el["on" + ev] = fn;//其他方法都无效,默认采用DOM0级方法,使用方括号语法将属性名指定为事件处理程序
}
};
2. jQuery $(document).ready(..)
мы все знакомы$(document).ready(..)
. В исходном коде это фактически обеспечивается вызываемым методомbindReady()
:
События загрузки используют два метода
:window.onload()
а также$(document).ready()
bindReady: function() {
...
if ( document.addEventListener ) {
// Use the handy event callback
document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
// A fallback to window.onload, that will always work
window.addEventListener( "load", jQuery.ready, false );
// If IE event model is used
} else if ( document.attachEvent ) {
document.attachEvent( "onreadystatechange", DOMContentLoaded );
// A fallback to window.onload, that will always work
window.attachEvent( "onload", jQuery.ready );
Facade
Внешний вид широко используется вjQuery
библиотека для удобства использования. Например, мы используемjQuery
из$(el).css()
или$(el).animate()
и т.п. метод.
чтобы нам не приходилось вручнуюjQuery
В ядре вызываются многие внутренние методы для реализации определенного поведения и в то же время избегания ручного иDOM API
взаимодействовать.
Похожие также
D3.js
3. Режим адаптера:Adapter Pattern
- Традиционный: Адаптация к проблеме несовместимости между двумя или более интерфейсами классов.
-
JS
: он может дополнительно адаптироваться к двум или более базам кода, внешним и внутренним данным и т. д.
Когда использовать Часто используемые адаптеры:
- Новые компоненты должны быть интегрированы и работать с существующими компонентами в приложении.
- Рефакторинг, при котором части программы переписываются с улучшенным интерфейсом, но старому коду по-прежнему нужен исходный интерфейс.
1. jQuery.fn.css()
нормализованное отображение
// Cross browser opacity:
// opacity: 0.9; Chrome 4+, FF2+, Saf3.1+, Opera 9+, IE9, iOS 3.2+, Android 2.1+
// filter: alpha(opacity=90); IE6-IE8
// Setting opacity
$( ".container" ).css( { opacity: .5 } );
// Getting opacity
var currentOpacity = $( ".container" ).css('opacity');
Внутренне реализовано как:
get: function( elem, computed ) {
return ropacity.test( (
computed && elem.currentStyle ?
elem.currentStyle.filter : elem.style.filter) || "" ) ?
( parseFloat( RegExp.$1 ) / 100 ) + "" :
computed ? "1" : "";
},
set: function( elem, value ) {
var style = elem.style,
currentStyle = elem.currentStyle,
opacity = jQuery.isNumeric( value ) ?
"alpha(opacity=" + value * 100 + ")" : "",
filter = currentStyle && currentStyle.filter || style.filter || "";
style.zoom = 1;
// 如果将不透明度设置为1,则移除其他過濾器
//exist - attempt to remove filter attribute #6652
if ( value >= 1 && jQuery.trim( filter.replace( ralpha, "" ) ) === "" ) {
style.removeAttribute( "filter" );
if ( currentStyle && !currentStyle.filter ) {
return;
}
}
// otherwise, set new filter values
style.filter = ralpha.test( filter ) ?
filter.replace( ralpha, opacity ) :
filter + " " + opacity;
}
};
2. Vue
серединаcomputed
yck - "Путь фронтенд-интервью"
существуетVue
На самом деле, мы часто используем шаблон адаптера.
Например, родительский компонент передает атрибут временной метки дочернему компоненту, и временная метка должна быть преобразована в обычное отображение даты внутри компонента, которое обычно используется.computed
Для преобразования этот процесс использует шаблон адаптера.
4. Режим прокси:Proxy Pattern
Предоставляет прокси для других объектов для управления доступом к этому объекту.
Вы можете детально контролировать методы доступа к классу (объекту),Предварительная обработка перед вызовом этого метода (унифицированный код процесса помещается в агент для обработки). Выполните постобработку после вызова этого метода.Например: агент звезды, агент арендного дома и т. д. — все агенты.
В чем смысл использования режима прокси?
-
«Принцип единой ответственности»: объектно-ориентированный дизайн поощряет распределение различных обязанностей по мелкозернистым объектам. Прокси получает функции на основе исходного объекта, не затрагивая исходный объект, что соответствует концепции проектирования слабой связи и высокой степени связности. .
-
Соблюдайте принцип «открыто-закрыто»: прокси можно удалить из программы в любой момент без модификации других частей кода.В реальных сценариях могут быть разные причины того, что прокси больше не нужен с итерацией версии , то вы можете легко заменить прокси-объект вызовом исходного объекта.
Функции:
- Устранение связи между системами и высокой стоимостью системных ресурсов
- Через прокси-объект можно защитить прокси-объект, чтобы на его расширяемость не влиял внешний мир.
- В js его выполнение часто зависит от браузера
- Прокси события использует шаблон прокси.
Классификация:
- удаленный прокси (
Remote Proxy
): предоставляет локальный прокси-объект для объекта, расположенного в другом адресном пространстве. - виртуальный агент (
Virtual Proxy
): Если вам нужно создать объект с большим потреблением ресурсов, сначала создайте объект с относительно небольшим потреблением для представления, а реальный объект будет создаваться только при необходимости. - средство защиты (
Protect Proxy
): Управляет доступом к объекту и может предоставлять разные уровни прав использования разным пользователям. - буферный прокси (
Cache Proxy
): Предоставляет место для временного хранения результатов целевой операции, чтобы несколько клиентов могли совместно использовать эти результаты. - Умный прокси-сервер котировок (
Smart Reference Proxy
): при ссылке на объект предоставьте некоторые дополнительные операции, такие как запись количества вызовов объекта.
недостаток::
-
Из-за добавления прокси-объектов между клиентом и реальной темой некоторые типы прокси-шаблонов могут замедлять обработку запросов, например прокси-серверы защиты.
-
Реализация шаблонов прокси требует дополнительной работы, а некоторые шаблоны прокси сложны в реализации, например удаленные прокси.
Наиболее часто используемая передняя частьвиртуальный агент,агент защиты,буферный прокси
1. ES6
серединаProxy
ES6
При условииProxy
Конструкторы позволяют нам легко использовать шаблон прокси:
// target: 表示所要代理的对象,handler: 用来设置对所代理的对象的行为。
let proxy = new Proxy(target, handler);
2. Предварительная загрузка изображения
В настоящее время общий веб-сайт будет иметь механизм предварительной загрузки изображения, то есть перед загрузкой реального изображения используется изображение хризантемы (круглое изображение gif), чтобы указать, что изображение загружается.
const img = new Image();
img.src = '/some/big/size/image.jpg';
document.body.appendChild(img);
Создайте узел виртуального образаvirtualImg
И построить для создания прокси-функции:
// 图片懒加载: 虚拟代理
const createImgProxy = (img, loadingImg, realImg) => {
let hasLoaded = false;
const virtualImg = new Image();
virtualImg.src = realImg;
virtualImg.onload = () => {
Reflect.set(img, 'src', realImg);
hasLoaded = true;
}
return new Proxy(img, {
get(obj, prop) {
if (prop === 'src' && !hasLoaded) {
return loadingImg;
}
return obj[prop];
}
});
Наконец, замените исходный узел изображения прокси-изображением для вызова:
const img = new Image();
const imgProxy = createImgProxy(img, '/loading.gif', '/some/big/size/img.jpg');
document.body.appendChild(imgProxy);
3. Пейджинговые данные: кеширующие прокси
Например, интерфейс и сервер разделены. При запросе данных с разбивкой на страницы из сервера, данные сервера должны запрашиваться повторно каждый раз, когда изменяется номер страницы. Мы можем кэшировать страницу и соответствующий Результаты. Когда та же страница запрашивается, она больше не будет использоваться. Вместо этого интерфейс бэкенда запроса извлекает данные из кеша.
const getFib = (number) => {
if (number <= 2) {
return 1;
} else {
return getFib(number - 1) + getFib(number - 2);
}
}
const getCacheProxy = (fn, cache = new Map()) => {
return new Proxy(fn, {
apply(target, context, args) {
const argsString = args.join(' ');
if (cache.has(argsString)) {
// 如果有缓存,直接返回缓存数据 console.log(`输出${args}的缓存结果: ${cache.get(argsString)}`);
return cache.get(argsString);
}
const result = fn(...args);
cache.set(argsString, result);
return result;
}
})
}
const getFibProxy = getCacheProxy(getFib);
getFibProxy(40); // 102334155getFibProxy(40); // 输出40的缓存结果: 102334155
4. Брокер событий
Прокси события использует шаблон прокси.
<ul id="ul">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
<script>
let ul = document.querySelector('#ul')
ul.addEventListener('click', (event) => {
console.log(event.target);
})
</script>
Привязав событие к родительскому узлу, позвольте родительскому узлу действовать как прокси для получения фактического щелкнутого узла.
5. Шаблон декоратора:Decorator Pattern
На основе того, что исходный объект не изменяется, путем его обертывания и расширения (добавления свойств или методов) исходный объект может удовлетворить более сложные потребности пользователей.
Декораторы аналогичны концепции функций высшего порядка. Декоратор принимает базовую форму в качестве параметра, добавляет к ней обработку и возвращает ее. преимущество:
- Преимущество в том, что основная ответственность класса (функция) отделена от функции оформления.
вопрос:
- Цепочка оформления перекрывает область действия функции, и если она слишком длинная, это также вызовет проблемы с производительностью.
существуетJavaScript
середина:
- Шаблон декоратора представляет собой более гибкую альтернативу наследованию.
- Декоратор используется для обертывания объектов с тем же интерфейсом и для добавления новых функций в виде перегруженных методов.Этот режим может добавлять собственное поведение перед декорированным объектом или за ним для достижения определенной цели.
Ядро состоит в том, чтобы кэшировать последнюю функцию
1. Простой пример
Возьмем простой пример:
var xiaoming = function () {
this.run = function () {
return '跑步'
},
this.eat = function () {
return: '吃饭'
}
}
// 小明可以跑步,也可以吃饭
// 下面是一个装饰类,给小明进行装饰
var decor = function (xiaoming) {
this.run = function () {
return xiaoming.run + '很快'
}
this.eat = function () {
return xiaoming.eat + '很多'
}
}
Через класс украшения реализуется украшение класса Сяомин.
2. TypeScript
модификатор функции:@
«@» — это не столько модифицированная функция, сколько ссылка и вызов функции, которую она модифицирует.
Или опишите его на просторечии: @: «Меня окружает следующее».
Например, в следующем фрагменте кода две функции в нем не вызываются, и будут выводиться результаты:
test(f){
console.log("before ...");
f()
console.log("after ...");
}
@test
func(){
console.log("func was called");
}
Запустите его напрямую и выведите результат:
before ...
func was called
after ...
3. React
Шаблон декоратора в
существуетReact
, шаблон декоратора везде:
import React, { Component } from 'react';
import {connect} from 'react-redux';
class App extends Component {
render() {
//...
}
}
// const mapStateToProps
// const actionCreators
export default connect(mapStateToProps,actionCreators)(App);
Ant Design
Последний шаг в создании формы — это шаблон декоратора.
class CustomizedForm extends React.Component {}
CustomizedForm = Form.create({})(CustomizedForm);
6. Режим моста:Bridge Pattern
Шаблон моста отделяет уровень реализации от подуровня абстракции, так что две части могут быть изменены независимо.
Этот режим включает в себя следующие роли:
-
Abstraction
(абстрактный класс) -
RefinedAbstraction
(Расширить абстрактный класс) -
Implementor
(реализация интерфейса класса) -
ConcreteImplementor
(конкретный класс реализации)
Приложение записывает в определенный API базы данных, например.ODBC
, но после этого API каждая реализация драйвера находится для каждого поставщика базы данных (SQL Server,MySQL,Oracle
д.), совершенно разные.
- Чаще встречается при разработке драйверов, в
JavaScript
редко в. - Кроссплатформенный дизайн некоторых программ иногда также применяет режим моста.
1. Замена темы сайта
На большом веб-сайте разные модули могут иметь разные темы, а также дневные/ночные или выбранные пользователем темы.
Создание нескольких копий каждой страницы для каждой темы явно нецелесообразно, и режим моста — лучший выбор:
Различные модули:
class About{
constructor(theme) {
this.theme = theme
}
getContent() {
return "About page in " + this.theme.getColor()
}
}
class Careers{
constructor(theme) {
this.theme = theme
}
getContent() {
return "Careers page in " + this.theme.getColor()
}
}
и разные темы:
class DarkTheme{
getColor() {
return 'Dark Black'
}
}
class LightTheme{
getColor() {
return 'Off white'
}
}
class AquaTheme{
getColor() {
return 'Light blue'
}
}
Создайте тему:
const darkTheme = new DarkTheme()
const about = new About(darkTheme)
const careers = new Careers(darkTheme)
console.log(about.getContent() )// "About page in Dark Black"
console.log(careers.getContent() )// "Careers page in Dark Black"
7. Комбинированный режим:Composite Pattern
- Также известный как шаблон «часть-целое», объекты объединяются в древовидную структуру для представления иерархии «часть-целое».
- Сделайте так, чтобы пользователи согласовывали использование отдельных объектов и составных объектов. (См. состав карточек и форм)
Этот режим включает в себя следующие роли:
-
Component
- Объявить интерфейс объектов в композиции и реализовать поведение по умолчанию (на основеComposite
) -
Leaf
- представляет исходный объект в композиции -
Composite
- существуетComponent
Реализовать дочерние операции в интерфейсе и хранитьLeaf(primitive)
объект.
1. Структура каталогов файлов в операционной системе
Файловая структура компьютера является примером шаблона композиции.
Если вы удалите папку, все содержимое этой папки также будет удалено, верно? По сути, так работает комбинированный режим. тыВы можете вызывать составные объекты выше в дереве структуры, и сообщения будут перемещаться вниз по этой иерархии.
2. Пакетные операцииDOM
Теория и практика шаблонов проектирования Javascript: шаблон композиции
HTML
ДокументацияDOM
Структура представляет собой естественную древовидную структуру, и самые основные элементы впиваются в дерево DOM, которое в конечном итоге формируется.DOM
Документация, очень полезная для комбинирования шаблонов.
наш обычныйjQuery
Библиотеки классов, в которых чаще применяется комбинированный паттерн, например, часто реализуется следующий код:
$(".test").addClass("noTest").removeClass("test");
независимо от $(“.test”)
Будь то один элемент или несколько элементов, в конечном итоге это достигается за счет унифицированногоaddClass
а такжеremoveClass
интерфейс для вызова.
Давайте просто смоделируемaddClass
Реализация:
var addClass = function (eles, className) {
if (eles instanceof NodeList) {
for (var i = 0, length = eles.length; i < length; i++) {
eles[i].nodeType === 1 && (eles[i].className += (' ' + className + ' '));
}
}
else if (eles instanceof Node) {
eles.nodeType === 1 && (eles.className += (' ' + className + ' '));
}
else {
throw "eles is not a html node";
}
}
addClass(document.getElementById("div3"), "test");
addClass(document.querySelectorAll(".div"), "test");
дляNodeList
илиNode
Например, все клиентские вызовы используются одинаково.addClass
Этот интерфейс, это самая основная идея комбинированного режима,Последовательное использование частей и целых.
8. Режим наилегчайшего веса:Flyweight Pattern
Наилегчайший вес (flyweight
) режим — это режим, используемый для оптимизации производительности, "fly
«Вот значение слова «муха», что означает «легковес».
- В основном используется для уменьшения количества создаваемых объектов, чтобы уменьшить объем памяти и повысить производительность.
- Используйте методы совместного использования для эффективной поддержки большого количества мелких объектов.
В основе шаблона Flyweight лежит использование методов совместного использования для эффективной поддержки большого количества мелких объектов.
Шаблон Flyweight очень полезен, если использование памяти слишком велико из-за создания большого количества однотипных объектов в системе. существуетJavaScript
, браузеры, особенно мобильные браузеры, не выделяют много памяти, поэтому то, как экономить память, стало очень значимой вещью.
Шаблон Flyweight выполняет следующие функции:
- Клиент: класс, используемый для вызова Flyweight Factory для получения внутренних данных, обычно объектов, требуемых приложением.
- Фабрика наилегчайшего веса: класс для хранения данных наилегчайшего веса
- Легковесные классы: классы, содержащие внутренние данные
1. Простой пример
В следующем примере мы создаем класс «Книга» для работы с конкретными книгами, а затем создаем класс «Книга».BookFactory
", чтобы управлять тем, как создаются эти объекты Book.
Для повышения производительности памяти объекты используются повторно, если экземпляр одного и того же объекта создается дважды.
class Book {
constructor(title, isbn, author, ratings) {
this.title = title;
this.isbn = isbn;
this.author = author;
this.ratings = ratings;
}
getAverageReview() {
let averageReview = (this.ratings.reduce((a,b) => a+b)) / this.ratings.length
return averageReview;
}
}
class BookFactory {
constructor() {
this._books = [];
}
createBook(title, isbn, author, ratings) {
let book = this.getBookBy(isbn);
if (book) { //重用对象
return book;
} else {
const newBook = new Book(title, isbn, author, ratings);
this._books.push(newBook);
return newBook;
}
}
getBookBy(attr) {
return this._books.find(book => book.attr === attr);
}
}
2. Реализация идей онлайн-форм
Откройте Google Таблицы, извлеките и распечатайте элемент узла.
Вы можете видеть, что даже если вы прокрутите до тысячи строк, они просто разделяют два представления.
Режим облегченного веса используется для предотвращения задержек при бесконечной прокрутке.
Вот фиктивная реализация:
Сначала HTML<section id="app">
<table id="table"></table>
<div class="controls">
<input type="range" name="scroll" id="scroll" value="0">
</div>
</section>
стиль:
#app {
position: relative;
padding: 30px 0 30px 10px;
#table {
padding: 20px;
border-radius: 10px;
min-width: 450px;
transition: background 0.5s;
background: rgba(73, 224, 56, 0.1);
&.low-range {
background: rgba(73, 224, 56, 0.47);
td {
border-bottom: 1px solid rgba(73, 224, 56, 0.9)
}
}
&.mid-range {
background: rgba(224, 196, 56, 0.47);
td {
border-bottom: 1px solid rgba(224, 196, 56, 0.9)
}
}
&.high-range {
background: rgba(224, 56, 56, 0.47);
td {
border-bottom: 1px solid rgba(224, 56, 56, 0.9)
}
}
&.ultra-high-range {
background: rgba(224, 56, 56, 0.9);
td {
border-bottom: 1px solid black
}
}
td {
border-bottom: 1px solid black;
padding: 10px;
font-weight: bold;
}
}
.controls {
padding-top: 20px;
#scroll {
width: 450px;
box-sizing: border-box;
}
}
}
Реализация логики, пожалуйста, съешьте с комментариями:
// 生成单元格实例
const makeRowCells = data => data.map(value => new Cell(value));
// 定义常量
const scrollViewport = 10; // 当前表格视图大小
const tableSize = 2000; // 行数
let scrollIndex = 0; // 初始滚动索引
let DATA = []; // 初始数据集
while (DATA.length < scrollViewport) {
const unit = DATA.length * 10;
DATA.push('12345678'.split('').map(() => unit));
}
/**
* cell类 - 列
*/
class Cell {
constructor(content) {
this.content = content;
}
// 更新列
updateContent(content) {
this.content = content;
this.cell.innerText = content;
}
// 渲染列
render() {
const cell = document.createElement('td');
this.cell = cell;
cell.innerText = this.content;
return cell;
}
}
/**
* row类 - 行
*/
class Row {
constructor(cellItems) {
this.cellItems = cellItems;
}
// 更新行
updateRowData(newData) {
this.cellItems.forEach((item, idx) => {
item.updateContent(newData[idx]);
});
}
// 渲染行
render() {
const row = document.createElement('tr');
this.cellItems.forEach(item => row.appendChild(item.render()));
return row;
}
}
/**
* 表格类
*/
class Table {
constructor(selector) {
this.$table = document.querySelector(selector);
}
// 添加行
addRows(rows) {
this.rows = rows;
this.rows.forEach(row => this.$table.appendChild(row.render()));
}
// 更新table数据
updateTableData(data) {
this.rows.forEach((row, idx) => row.updateRowData(data[idx]));
}
}
// 实例化新表
const table = new Table('#table');
// 匹配滚动条的DOM
const scrollControl = document.querySelector('#scroll');
// 在table下添加单元格行
table.addRows(
DATA.map(dataItem => new Row(makeRowCells(dataItem))));
const onScrollChange = event => {
// 为视图准备新数据
DATA = DATA.map((item, idx) => item.map(cell => parseInt(event.target.value, 10)*10 + idx*10));
// 更新当前table的数据
table.updateTableData(DATA);
// 添加颜色区别样式
scrollIndex = event.target.value;
if (event.target.value >= 0) {
table.$table.classList = 'low-range';
}
if (event.target.value > tableSize * 0.4) {
table.$table.classList = 'mid-range';
}
if (event.target.value > tableSize * 0.7) {
table.$table.classList = 'high-range';
}
if (event.target.value > tableSize * 0.9) {
table.$table.classList = 'ultra-high-range';
}
};
// 设置滚动条最小和最大范围
scrollControl.setAttribute('min', 0);
scrollControl.setAttribute('max', tableSize);
// 添加滚动事件
scrollControl.addEventListener('input', onScrollChange);
// 初始化事件
const event = {target: {value: 0}};
onScrollChange(event);
9. Заключение и ссылки
До сих пор говорилось о паттерне структурного проектирования (вода), а о паттерне Flyweight стоит написать в блог отдельно.
Справочная статья- Интенсивный курс по шаблонам проектирования JavaScript
- Теория и практика шаблонов проектирования Javascript: шаблон легковеса
- Easy patterns: Flyweight
- Composite design pattern
- Теория и практика шаблонов проектирования Javascript: шаблон композиции
- yck - "Путь фронтенд-интервью"
❤️ После прочтения трех вещей
Если вы найдете этот контент вдохновляющим, я хотел бы пригласить вас сделать мне три небольших одолжения:
- Ставьте лайк, чтобы больше людей увидело этот контент
- Обратите внимание на паблик «Учитель фронтенд-убеждения», и время от времени делитесь оригинальными знаниями.
- Также смотрите другие статьи
- Те шаблоны проектирования, которые вы используете непреднамеренно (1) - шаблоны создания
- «Король библиотеки визуализации данных» D3.js Быстрое начало работы с приложением Vue
- Руководство "True® Full Stack Road" для веб-интерфейсной разработки
- «Практика Vue» — плагин Vue CLI за 5 минут
- Вооружите свой интерфейсный проект «Практикой Vue»
- «Intermediate and Advanced Front-End Interview» JavaScript Рукописный код Invincible Cheats
- «Узнайте из исходного кода» ответы на вопросы Vue, которые интервьюеры не знают
- JS-операция «Узнать из исходного кода» в исходном коде Vue
- Правильная позиция для обновления vue-cli3 в проекте "Vue Practice"
- Почему вы до сих пор не можете понять цепочку областей видимости JavaScript?
Закулисный ответ публичного аккаунта "Шаблоны проектирования” Получите авторский старательно самодельныйкарта разума.