系列首发于公众号『非同质前端札记』 ,若不想错过更多精彩内容,请“星标”一下,敬请关注公众号最新消息。
var createImg = (function () { var imgNode = document.createElement("img"); document.appendChild(imgNode); return { setSrc: function (src) { imgNode.src = src; }, }; })(); var proxyImg = (function () { var img = new Image(); img.onload = function () { createImg.setSrc(this.src); }; return { setSrc: function (src) { createImg.setSrc("loading.gif"); img.src = src; }, }; })(); proxyImg.setSrc("bg.jpg");
var createImg = (function () { var imgNode = document.createElement("img"); document.appendChild(imgNode); var img = new Image(); img.onload = function () { imgNode.src = img.src; }; return { setSrc: function (src) { imgNode.src = "loading.gif"; img.src = src; }, }; })(); createImg.setSrc("bg.jpg");
对于一个类而言,应该仅有一个引起它改变的入口
。如果一个对象承担了很多职责,那这个对象将变得很臃肿,那引起它变化的原因可能会有很多个。如果一个对象承担的职责过多,就等于把这些职责耦合在了一起,这种耦合会导致代码很脆弱和低内聚的设计。// 真实对象类 - 用于存储数据 class Storage { constructor() { this.data = []; } storeData(data) { // 模拟存储数据的操作 console.log(`Storing data: ${data}`); this.data.push(data); } displayData() { console.log("Stored data:", this.data); } } // 代理对象类 - 延迟存储操作 class ProxyStorage { constructor() { this.storage = new Storage(); this.pendingData = []; this.timer = null; this.delay = 5000; // 定时存储的延迟时间设定为5秒 } storeData(data) { this.pendingData.push(data); this.scheduleStorage(); } scheduleStorage() { if (!this.timer) { this.timer = setTimeout(() => { this.flushPendingData(); this.timer = null; }, this.delay); } } flushPendingData() { this.pendingData.forEach((data) => { this.storage.storeData(data); }); this.pendingData = []; } displayData() { this.storage.displayData(); } } // 使用代理对象进行数据存储 const proxyStorage = new ProxyStorage(); // 模拟数据产生 function generateData() { const data = Math.random(); // 这里使用随机数作为数据示例 // 将数据添加到带存储的数据队列中,并启动定时器来延迟存储操作。当在延迟时间内再次调用 storeData 时,则会每次更新带存储的数据队列数据。当定时器触发时,代理对象则会调用 Storage 对象的存储方法,将所有带存储的数据存储起来。 proxyStorage.storeData(data); } // 调用 generateData() 来模拟产生数据 // 在某一个时间段内连续产生数据,但实际触发存储的时间是延迟了的 setInterval(generateData, 1000); // 模拟数据存储结束后,手动调用 displayData() 显示已存储的数据 setTimeout(() => { proxyStorage.displayData(); }, 15000); // 这里设定15秒后结束数据存储并展示存储结果
// 真实对象类 - 用于存储数据 class Storage { constructor() { this.data = []; } storeData(data) { // 模拟存储数据的操作 console.log(`Storing data: ${data}`); this.data.push(data); } displayData() { console.log("Stored data:", this.data); } } // 代理对象类 - 延迟存储操作和定时暂停 class ProxyStorage { constructor() { this.storage = new Storage(); this.pendingData = []; this.timer = null; this.delay = 5000; // 定时存储的延迟时间设定为5秒 this.paused = false; // 初始状态为未暂停 } storeData(data) { this.pendingData.push(data); this.scheduleStorage(); } scheduleStorage() { if (!this.paused && !this.timer) { this.timer = setTimeout(() => { this.flushPendingData(); this.timer = null; }, this.delay); } } flushPendingData() { this.pendingData.forEach((data) => { this.storage.storeData(data); }); this.pendingData = []; } pause() { this.paused = true; clearTimeout(this.timer); this.timer = null; } restart() { this.paused = false; this.scheduleStorage(); } stop() { this.pause(); this.pendingData = []; } displayData() { this.storage.displayData(); } } // 使用代理对象进行数据存储 const proxyStorage = new ProxyStorage(); // 模拟数据产生 function generateData() { const data = Math.random(); // 这里使用随机数作为数据示例 proxyStorage.storeData(data); } // 调用 generateData() 来模拟产生数据 // 在某一个时间段内连续产生数据,但实际触发存储的时间是延迟了的 const intervalId = setInterval(generateData, 1000); // 模拟数据存储进行一段时间后,停止定时器并清空待存储的数据 setTimeout(() => { // proxyStorage.stop(); proxyStorage.pause(); console.log("Timer stopped and pending data cleared"); }, 8000); // 这里设定8秒后停止定时器和清空待存储的数据 // 模拟数据存储结束后,手动调用 displayData() 显示已存储的数据 setTimeout(() => { proxyStorage.displayData(); }, 15000); // 这里设定15秒后结束数据存储并展示存储结果 // 模拟数据存储恢复定时器 setTimeout(() => { proxyStorage.restart(); console.log("Timer restarted"); clearInterval(intervalId); }, 20000); // 这里设定20秒后恢复定时器
// input: const movieServiceProxy = new CachedMovieServiceProxy(); console.log(movieServiceProxy.getMovie(1)); // 输出电影信息并缓存 console.log(movieServiceProxy.getMovie(2)); // 输出电影信息并缓存 console.log(movieServiceProxy.getMovie(1)); // 从缓存中输出电影信息 // output: // Fetching movie with id 1 from the database... // Caching movie with id 1... { id: 1, title: "Movie A", director: "Director A" } // Fetching movie with id 2 from the database... // Caching movie with id 2... { id: 2, title: "Movie B", director: "Director B" } // Retrieving movie with id 1 from cache... { id: 1, title: "Movie A", director: "Director A" }
// 真实对象类 - 电影服务 class MovieService { constructor() { // 模拟电影数据 this.movies = [ { id: 1, title: "Movie A", director: "Director A" }, { id: 2, title: "Movie B", director: "Director B" }, { id: 3, title: "Movie C", director: "Director C" }, ]; } // 获取电影信息 getMovie(id) { console.log(`Fetching movie with id ${id} from the database...`); // 模拟从数据库获取电影信息的操作 const movie = this.movies.find((movie) => movie.id === id); return movie; } } // 代理对象类 - 缓存代理 class CachedMovieServiceProxy { constructor() { this.movieService = new MovieService(); this.cache = {}; } // 获取电影信息(代理方法) getMovie(id) { if (this.cache[id]) { // 如果缓存中有对应的电影信息,则直接返回缓存数据 console.log(`Retrieving movie with id ${id} from cache...`); return this.cache[id]; } else { // 否则,调用真实对象的方法获取电影信息,并将结果存入缓存 const movie = this.movieService.getMovie(id); console.log(`Caching movie with id ${id}...`); this.cache[id] = movie; return movie; } } } // 使用代理对象获取电影信息 const movieServiceProxy = new CachedMovieServiceProxy(); console.log(movieServiceProxy.getMovie(1)); // 第一次请求,从真实对象获取并缓存 console.log(movieServiceProxy.getMovie(2)); // 第二次请求,从真实对象获取并缓存 console.log(movieServiceProxy.getMovie(1)); // 第三次请求,从缓存中获取
曾探
大佬的《JavaScript 设计模式与开发实践》。文章仅做个人学习总结和知识汇总Q:(question)
R:(result)
A:(attention matters)
D:(detail info)
S:(summary)
Ana:(analysis)
T:(tips)