嘿ð
自从我开始专业编码以来已经有几年了。我一直在对话中听过“设计模式”一词,但从未真正尝试学习它们。直到最近,一位高级开发人员在工作中审查了我的公关,并留下了一条评论,说“……试图使这成为单身人”。这使我终于对这个话题进行了一些挖掘。
我经历了许多资源,例如崩溃课程,文章和YouTube视频。令我惊讶的是,我发现我一直在不知不觉中使用其中一些模式。我很确定您也会有同样的感觉。我肯定有一些新的想法/模式,我发现有用。在这篇文章中,我将尝试介绍一些模式,这些模式肯定会帮助您成为更好的开发人员,甚至引起您的好奇心,以了解更多此类模式。
什么是设计模式?
设计模式是针对常见软件架构问题进行战斗测试的蓝图。他们提供了一个抽象概念来解决问题。由开发人员建立在他们身上并提出实际解决方案。
与算法不同,这些模式没有提供清晰的步骤来解决问题。这些只是您可以根据需要进一步扩展的设计想法。
其中一些模式在下面列出。
1.单例图案
singleton模式可确保类只有一个实例,并且该实例在整个应用程序中都可以在全球范围内访问。此单例的导入均参考相同的实例。
class LocalStorage {
constructor() {
if (!LocalStorage.instance) {
LocalStorage.instance = this;
}
return LocalStorage.instance;
}
setItem(key, value) {
// save to some storage
console.log(`Item saved: ${key} - ${value}`)
}
getItem(key) {
console.log(`Getting item ${key} from storage.`);
// get from storage and return
}
}
const store = Object.freeze(new LocalStorage());
export default store;
在本地存储周围实现自己的包装器是单例模式的一个很好的例子。我们要使用宽的同一实例应用程序。
在这里,我们创建一个LocalStorage
实例并导出它。无法创建此类的另一个对象。即使他们尝试过,constructor
也会阻止它们,因为它检查了实例是否已经存在。
最后,Object.freeze
是蛋糕上的樱桃。它将阻止对我们的对象进行任何修改。
ðâstrong>使用:
- 获得单个实例的全局访问点。
- 单身人士仅在请求时才初始化一次。因此,它节省了内存空间。
ð»缺点:
- 很难为单身人士编写测试,因为我们不能每次创建新实例。所有测试都取决于一个全局实例。
2.代理模式
代理模式,让您为目标对象提供替代/包装器。使用这种模式可以拦截或重新定义与目标对象的所有交互。
JavaScript具有内置的Proxy
和Reflect
对象来实现此模式。
const target = {
name: 'John',
age: 82
}
const handler = {
get: (target, key) => {
console.log(`Getting key: ${key}`);
return target[key];
},
set: (target, key, value) => {
console.log(`Setting ${value} on key ${key}`);
target[key] = value;
return true;
}
};
const proxyObject = new Proxy(target, handler);
console.log(proxyObject.name);
在上面的代码中,我们向Proxy
提供一个target
对象和一个handler
对象。 handler
对象可用于覆盖-get
,set
,has
,deleteProperty
等对象方法的实现。
另外,如果我们不希望像上面的示例一样修改这些方法的行为,则可以使用Reflect
。它具有完全相同的功能。
const handler = {
get: (target, key) => {
console.log(`Getting key: ${key}`);
return Reflect.get(target, key);
},
set: (target, key, value) => {
console.log(`Setting ${value} on key ${key}`);
return Reflect.set(target, key, value);
}
};
ðâstrong>使用:
- 访问控制
- 记录请求
- Caching
- 懒惰初始化
ð»缺点:
- 这可能导致性能问题。
- 该代码可能会随着太多代理而变得复杂。
3.观察者模式
观察者模式是一种设计模式,其中称为主题或发布者的对象维护其依赖者列表,称为观察者或订阅者,并自动通知他们对其状态的任何更改。当另一个对象的状态更改时,可以通知多个对象,而无需直接引用彼此。
这个模式的简单示例看起来像这样。
class Button {
constructor() {
this.subscribers = [];
}
subscribe(fn) {
this.subscribers.push(fn);
}
doSomething() {
const data = { x: 1 };
this.notify(data);
}
notify(data) {
this.subscribers.forEach(fn => fn(data));
}
}
class EventHandler {
listener(data) {
console.log("Received:", data);
}
}
const button = new Button();
const eventHandler = new EventHandler();
button.subscribe(eventHandler.listener);
button.doSomething();
// Received: {x : 1}
在此示例中,Button
跟踪其所有订户,并通过调用notify
方法通知他们任何更改。
ðâstrong>使用:
- 当一个对象的状态变化对于其他对象很重要,并且这些对象事先未知时,可以使用此模式。
ð»缺点:
- 这可能会导致某些性能问题,如果订户过多或
notify
函数中的某些复杂代码。 - 无法预测这些订户收到的通知的顺序。
4.工厂模式
出厂模式是一种设计模式,它提供了一种创建对象的方法,而无需指定将要创建的确切对象类别。相反,工厂类/功能负责创建对象。
imo,这是此处讨论的所有模式中最简单的一种。你们中许多人已经在使用它很有可能。
class Car {
constructor(make, model) {
this.make = make;
this.model = model;
}
}
class Truck {
constructor(make, model, payloadCapacity) {
this.make = make;
this.model = model;
this.payloadCapacity = payloadCapacity;
}
}
function vehicleFactory(type, make, model, payloadCapacity) {
switch (type) {
case "car":
return new Car(make, model);
case "truck":
return new Truck(make, model, payloadCapacity);
default:
throw new Error(`Invalid vehicle type: ${type}`);
}
}
const car = vehicleFactory("car", "Toyota", "Camry");
console.log(car);
// Output: Car { make: "Toyota", model: "Camry" }
const truck = vehicleFactory("truck", "Ford", "F-150", 2000);
console.log(truck);
// Output: Truck { make: "Ford", model: "F-150", payloadCapacity: 2000 }
而不是直接访问Car
或Truck
类,而是将该任务委派给我们的出厂功能。
ðâstrong>使用:
- 几乎可以在没有任何开销的任何地方使用。
- 执行干燥。
ð»缺点:我看不到! ð
5.原型模式
原型图案是一种设计模式,可以克隆或复制对象,而不是从头开始创建。原型设计模式依赖于JavaScript prototypical inheritance。此模式主要用于在性能密集型情况下创建对象。
JavaScript中原型模式的一个示例是代表基本形状(例如矩形)的原型对象,以及根据原型创建新形状的函数。
const shapePrototype = {
width: 0,
height: 0,
area: function() {
return this.width * this.height;
}
};
function createShape(shape) {
const newShape = Object.create(shapePrototype);
newShape.width = shape.width;
newShape.height = shape.height;
return newShape;
}
const shape1 = createShape({width: 5, height: 10});
console.log(shape1.area());
// Output: 50
const shape2 = createShape({width: 3, height: 4});
console.log(shape2.area());
// Output: 12
createShape
函数以对象为参数,该对象用于设置新形状的width
和height
属性。新形状对象从原型继承了area
方法。
您可以通过检查对象的原型来验证这一点。
console.log(shapePrototype.__proto__)
// This is for you to find out! ;)
console.log(shape1.__proto__)
// Output: {
// area: function() {
// return this.width * this.height;
// },
// height: 0,
// width: 0
// }
console.log(shape1.__proto__.__proto__ === shapePrototype.__proto__)
// Output: true
ðâstrong>使用:
- 内存有效,因为多个对象依赖相同的原型并共享相同的方法或属性。
ð»缺点:
- 如果有一个长长的原型链,很难知道某些属性来自何处。
总而言之,设计模式是组织和构造代码的强大工具,使其更可读,可维护和可重复使用。本文涵盖的五个模式只是JavaScript中许多设计模式的一些示例。通过了解这些模式以及如何应用它们,您可以提高代码的质量,并使其更加稳健和高效。
我希望这篇文章有所帮助且内容丰富。我将来将继续撰写有关其他设计模式的文章,并可以随意在LinkedIn和Twitter上与我建立联系,在那里我分享了我的工作和文章的想法和更新。
谢谢! ð