- 工厂模式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>01-工厂模式</title>
</head>
<body>
<div>
<h2>原理</h2>
<span>工厂模式通过使用工厂方法来创建对象,而不是直接使用new关键字。工厂方法根据输入参数的不同,决定创建哪个具体的对象实例,并将其返回。</span>
</div>
<div>
<h2>使用场景</h2>
<ul>
<li>当需要创建多个相似的对象时</li>
<li>当对象创建过程复杂或需要隐藏创建逻辑时</li>
<li>当希望通过一个公共的接口来创建对象时</li>
</ul>
</div>
<div>
<h2>优点</h2>
<ul>
<li>将对象的创建与使用代码分离,客户端只需关注接口而不需要关心具体的对象创建过程</li>
<li>可以通过工厂方法来创建不同类型的对象,提供灵活性和可扩展性</li>
</ul>
</div>
<script>
// 定义一个产品类
class Product {
constructor(name) {
this.name = name;
}
display() {
console.log(`Product: ${this.name}`);
}
}
// 定义工厂类
class Factory {
createProduct(name) {
return new Product(name);
}
}
// 使用工厂创建对象
const factory = new Factory();
const product1 = factory.createProduct('Product 1');
const product2 = factory.createProduct('Product 2');
product1.display();
product2.display();
</script>
</body>
</html>
- 单例模式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>02-单例模式</title>
</head>
<body>
<div>
<h2>原理</h2>
<span>单例模式确保一个类只有一个实例,并提供全局访问点以获取该实例。它通过私有化构造函数,限制外部直接创建对象,并体用一个静态方法来获取或创建唯一的实例</span>
</div>
<div>
<h2>使用场景</h2>
<ul>
<li>当需要一个全局对象来协调系统中的操作时</li>
<li>当需要频繁访问同一个对象实例时</li>
<li>当需要限制一个类只能有一个实例时</li>
</ul>
</div>
<div>
<h2>优点</h2>
<ul>
<li>提供了对唯一实例的全局访问,方便共享对象</li>
<li>避免了重复创建实例的开销,节省了内存和资源</li>
</ul>
</div>
<script>
class Singleton {
static instance = null;
constructor () {
if(Singleton.instance){
return Singleton.instance;
}
Singleton.instance = this;
}
}
// 获取实例
const instance1 = new Singleton();
const instance2 = new Singleton();
console.log(instance1 === instance2);
</script>
</body>
</html>
- 观察者模式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>03-观察者模式</title>
</head>
<body>
<div>
<h2>原理:</h2>
<span>观察者模式定义了对象之间一对多依赖关系,当一个对象的状态发生变化时,它的所有依赖者(观察者)都会被通知更新</span>
</div>
<div>
<h2>使用场景</h2>
<ul>
<li>当一个对象的变化需要通知其它对象,以便它们可以做出相应的响应时。</li>
<li>当对象之间的耦合度需要降低,使得它们之间可以独立的交互时</li>
</ul>
</div>
<div>
<h2>优点</h2>
<ul>
<li>实现了对象之间的松耦合,被观察者和观察者可以独立的演化和变化</li>
<li>可以轻松添加或移除观察者,以实现动态的发布-订阅机制</li>
</ul>
</div>
<script>
class Subject {
constructor(){
this.observers = [];
}
addObserver(observer) {
this.observers.push(observer);
}
removeObserver(observer) {
this.observers = this.observers.filter(obs => obs !== observer);
}
notifyObservers() {
this.observers.forEach(observer => observer.update());
}
}
class Observer {
constructor(name) {
this.name = name;
}
update () {
console.log(`Observer ${this.name} has been notified.`);
}
}
// 创建主题和观察者
const subject = new Subject();
const observer1 = new Observer('1');
const observer2 = new Observer('2');
// 注册观察者
subject.addObserver(observer1);
subject.addObserver(observer2);
// 通知观察者
subject.notifyObservers();
</script>
</body>
</html>
- 发布订阅模式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>04-发布订阅模式</title>
</head>
<body>
<div>
<h2>原理</h2>
<span>发布-订阅模式类似于观察者模式,但是发布者(或称为主题)不会直接通知特定的订阅者,而是通过消息代理(或称为事件总线)来分发和传递消息。订阅者可以根据自身的需求订阅感兴趣的消息</span>
</div>
<div>
<h2>使用场景</h2>
<ul>
<li>当一个对象的状态变化需要通知多个订阅者时</li>
<li>当需要将发布者和订阅者解耦,使他们可以独立的演化时</li>
<li>当希望在系统中引入中介层以提供更灵活的消息传递机制时</li>
</ul>
</div>
<div>
<h2>有点</h2>
<ul>
<li>解耦了发布者和订阅者,使他们可以独立的交互</li>
<li>提供了更灵活的消息传递机制,可以实现更复杂的事件处理逻辑</li>
</ul>
</div>
<script>
/** 原理:**/
class EventBus {
constructor() {
this.subscribers = {};
}
subscribe(eventName, callback) {
if(!this.subscribers[eventName]) {
this.subscribers[eventName] = [];
}
this.subscribers[eventName].push(callback);
}
unsubscribe(eventName, callback){
if(this.subscribers[eventName]){
this.subscribers[eventName] = this.subscribers[eventName].filter((cb) => cb!== callback);
}
}
publish(eventName, data) {
if(this.subscribers[eventName]){
this.subscribers[eventName].forEach(callback => callback(data));
}
}
}
// 创建事件总线
const eventBus = new EventBus();
// 订阅事件
const callback1 = (data) => console.log(`Subscriber 1 received: ${data}`);
const callback2 = (data) => console.log(`Subscriber 2 received: ${data}`);
eventBus.subscribe('event1', callback1);
eventBus.subscribe('event2', callback2);
// 发布事件
eventBus.publish('event1', 'Hello subscribers 1!');
eventBus.publish('event2', 'Hello subscribers 2!');
</script>
</body>
</html>
- 原型模式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>05-原型模式</title>
</head>
<body>
<div>
<h2>原理</h2>
<span>原型模式通过克隆现有对象来创建新对象,而不是依赖显式的实例化过程。每一个对象都可以作为另一个对象的原型,新对象会继承原型对象的属性和方法</span>
</div>
<div>
<h2>使用场景</h2>
<ul>
<li>当创建对象的过程比较昂贵或复杂时,而且新对象的创建与现有对象的状态无关时</li>
<li>当希望通过修改原型对象来影响所有克隆对象时</li>
<li>当需要避免使用new关键字直接实例化对象时</li>
</ul>
</div>
<div>
<h2>优点</h2>
<ul>
<li>避免了创建对象的昂贵或复杂过程,提高了性能和效率</li>
<li>可以通过修改原型对象来影响所有克隆对象,实现了对象状态的批量修改</li>
</ul>
</div>
<script>
class Prototype {
constructor(name) {
this.name = name;
}
clone () {
return Object.create(Object.getPrototypeOf(this));
}
}
// 创建原型对象
const prototype = new Prototype('Prototype');
// 克隆对象
const clone1 = prototype.clone();
const clone2 = prototype.clone();
console.log(clone1.name);
console.log(clone2.name);
</script>
</body>
</html>
- 适配器模式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>06-适配器模式</title>
</head>
<body>
<div>
<h2>原理</h2>
<span>适配器模式将一个类的接口转换成另一个接口,以满足客户端的需求。它通过创建一个适配器类来实现接口转换,并在适配器类中调用被适配类的方法。</span>
</div>
<div>
<h2>使用场景</h2>
<ul>
<li>当需要将一个已有类的接口转换成另一个接口时</li>
<li>当希望通过一个统一的接口来使用多个不兼容的类时</li>
<li>当需要在不影响现有代码的情况下,对已有类的方法进行扩展或修改时</li>
</ul>
</div>
<div>
<h2>优点</h2>
<ul>
<li>可以将已有类与新代码进行无缝衔接,使它们能够协同工作</li>
<li>可以实现对象之间的接口转换,提供了灵活性和可扩展性</li>
</ul>
</div>
<script>
class Adaptee {
specificRequest(){
return 'Specific request';
}
}
class Adapter {
constructor (adaptee) {
this.adaptee = adaptee;
}
request () {
return this.adaptee.specificRequest();
}
}
// 使用适配器
const adaptee = new Adaptee();
const adapter = new Adapter(adaptee);
console.log(adapter.request());
</script>
</body>
</html>
- 装饰者模式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>07-装饰者模式</title>
</head>
<body>
<div>
<h2>原理</h2>
<span>装饰者模式动态的给对象添加新的行为或功能,同时不改变其原始类结构。它通过创建一个装饰器类来包装原始对象,并在装饰器类中添加额外的行为</span>
</div>
<div>
<h2>使用场景</h2>
<ul>
<li>当需要在不改变现有对象结构的情况下,动态地给对下个你添加新的行为时</li>
<li>当希望通过透明的方式为对象添加功能,而不影响其使用方式和客户端代码时</li>
<li>当不适合使用子类来扩展对象功能时</li>
</ul>
</div>
<div>
<h2>优点</h2>
<ul>
<li>可以透明的扩展对象的功能,而不会影响客户端代码</li>
<li>允许通装饰器类组合和嵌套多个装饰器,实现复杂的功能组合</li>
</ul>
</div>
<script>
class Component {
operation () {
return `Component operation`;
}
}
class Decorator {
constructor(component) {
this.component = component;
}
operation () {
return `${this.component.operation()} + Decorator operation`;
}
}
// 使用装饰者
const component = new Component();
const decorator = new Decorator(component);
console.log(decorator.operation());
</script>
</body>
</html>
- 策略模式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>08-策略模式</title>
</head>
<body>
<div>
<h2>原理</h2>
<span>策略模式定义了一系列算法,将他们封装成独立的可互换的策略对象,并使得客户端可以在运行时动态的选择使用不同的策略。客户端通过与策略对下个你进行交互来实现不同的行为</span>
</div>
<div>
<h2>使用场景</h2>
<ul>
<li>当需要在多个算法或行为之间进行动态选择时</li>
<li>当希望将算法的实现与使用它的客户端代码分离,以便它们可以独立的演化和修改时</li>
<li>当不希望使用大量的条件语句来处理不同的情况时</li>
</ul>
</div>
<div>
<h2>优点</h2>
<ul>
<li>实现了算法的封装和多态性,可以根据需要灵活的切换算法</li>
<li>将算法的实现与使用它的客户端代码分离,使得他们可以独立演化和修改</li>
</ul>
</div>
<script>
class Strategy {
execute() {
// 策略执行的具体操作
}
}
class ConcreteStrategy1 extends Strategy {
execute() {
console.log('Strategy 1');
}
}
class ConcreteStrategy2 extends Strategy {
execute () {
console.log('Strategy 2');
}
}
// 使用策略
const strategy1 = new ConcreteStrategy1();
const strategy2 = new ConcreteStrategy2();
strategy1.execute();
strategy2.execute();
</script>
</body>
</html>
- 模块模式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>09-模块模式</title>
</head>
<body>
<div>
<h2>原理</h2>
<span>模块模式使用函数作用域和闭包来封装和组织代码,实现模块化和私有性。它通过返回一个包含公共方法和属性的对象,类来实现对外部的封装</span>
</div>
<div>
<h2>使用场景</h2>
<ul>
<li>当希望将相关的方法和属性封装在一个单独的对象中时</li>
<li>当希望限制对方法和属性的访问,并保持私有性时</li>
<li>当需要实现模块化,避免全局命名冲突和污染时</li>
</ul>
</div>
<div>
<h2>优点</h2>
<ul>
<li>将相关的方法和属性封装在一个单独的对象中,提供了组织和管理代码的方式</li>
<li>通过闭包实现了私有性,可以隐藏内部的实现细节,防止外部访问和修改</li>
</ul>
</div>
<script>
const module = (function () {
let privateVariable = 'Private';
function privateMethod() {
console.log('Private method');
}
return {
publicVariable: 'Public',
publicMethod: function () {
console.log('Public method');
}
}
})();
console.log(module.publicVariable);
module.publicMethod();
</script>
</body>
</html>
- 代理模式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>10-代理模式</title>
</head>
<body>
<div>
<h2>原理</h2>
<span>代理模式为一个对象提供一个代理或占位符,并控制对其的访问。代理对象可以在访问被代理对象之前或之后添加额外的逻辑,如延迟加载、权限控制、缓存等</span>
</div>
<div>
<h2>使用场景</h2>
<ul>
<li>当需要在访问对象之前或之后执行额外的操作时</li>
<li>当希望通过代理控制对对象的访问权限时</li>
<li>当需要延迟加载对象或实现缓存等功能时</li>
</ul>
</div>
<div>
<h2>优点</h2>
<ul>
<li>可以在访问对象之前或之后执行额外的操作,如延迟加载、权限控制、缓存等</li>
<li>提供了对真实对象的访问控制,可以限制对对象的直接访问</li>
</ul>
</div>
<script>
class RealSubject {
request() {
console.log('Real subject request');
}
}
class Proxy {
constructor(realSubject){
this.realSubject = realSubject;
}
request() {
// 在调用真实对象方法之前或之后执行额外操作
console.log('Proxy request');
this.realSubject.request();
}
}
// 使用代理
const realSubject = new RealSubject();
const proxy = new Proxy(realSubject);
proxy.request();
</script>
</body>
</html>
- 迭代器模式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>11-迭代器模式</title>
</head>
<body>
<div>
<h2>原理</h2>
<span>迭代器模式提供了一种访问集合对象元素的方式,而无需暴露集合的内部结构。它将迭代逻辑封装在迭代器对象中,客户端通过迭代器来遍历集合</span>
</div>
<div>
<h2>使用场景</h2>
<ul>
<li>
当集合对象的内部结构可能经常变化时,使用迭代器可以减少对客户端代码的影响
</li>
<li>
当需要对集合对下个你进行不同类型的遍历时,迭代器提供了统一的接口,使得遍历逻辑更加灵活和可扩展
</li>
<li>
当需要在遍历过程中对集合元素进行筛选、过滤或转换时,可以通过迭代器来实现
</li>
</ul>
</div>
<div>
<h2>优点</h2>
<ul>
<li>将遍历集合的责任从客户端代码中抽离出来,简化了客户端代码</li>
<li>隐藏了集合的内部结构,提供了更好的封装性和安全性</li>
<li>支持不同类型的集合,提供了统一的迭代接口</li>
</ul>
</div>
<script>
// 定义集合对象
class Collection {
constructor () {
this.items = [];
}
addItem(item) {
this.items.push(item);
}
getIterator(){
return new Iterator(this.items);
}
}
// 定义迭代器对象
class Iterator {
constructor (collection) {
this.collection = collection;
this.index = 0;
}
hasNext(){
return this.index < this.collection.length;
}
next () {
return this.collection[this.index++];
}
}
// 使用迭代器遍历集合
const collection = new Collection();
collection.addItem('Item 1');
collection.addItem('Item 2');
collection.addItem('Item 3');
const iterator = collection.getIterator();
while (iterator.hasNext()) {
console.log(iterator.next());
}
</script>
</body>
</html>
- 状态模式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>12-状态模式</title>
</head>
<body>
<div>
<h2>原理</h2>
<span>状态模式允许对象在内部状态发生改变时改变其行为,看起来就像是对象类发生了改变。它将每个状态封装在一个独立的类中,并允许对象在不同状态之间切换。</span>
</div>
<div>
<h2>使用场景</h2>
<ul>
<li>
当一个对象的行为取决于其内部状态,并在不同状态下具有不同行为时,可以使用状态模式来管理状态转换和行为。
</li>
<li>
当需要在运行时根据条件动态的改变对象的行为时,状态模式提供了一种优雅的方式来实现
</li>
<li>
当对象有大量的条件语句,而且随着状态的增加会变得更加复杂时,可以使用状态模式来简化代码结构
</li>
</ul>
</div>
<div>
<h2>优点</h2>
<ul>
<li>
将对象的状态和行为封装在独立的类中,提高了代码的可读性和可维护性
</li>
<li>
避免了使用大量的条件语句来处理不同的状态,简化了代码结构
</li>
<li>
新增或修改状态变得更加容易,不会对其他状态产生影响
</li>
</ul>
</div>
<script>
// 定义状态接口
class State {
handle (context) {
// 默认实现
}
}
// 定义具体状态类
class ConcreteStateA extends State {
handle(content) {
console.log('State A');
context.setState(new ConcreteStateB());
}
}
class ConcreteStateB extends State {
handle(context) {
console.log('State B');
context.setState(new ConcreteStateA());
}
}
// 定义上下文类
class Context {
constructor(){
this.state = new ConcreteStateA();
}
setState(state){
this.state = state;
}
request() {
this.state.handle(this);
}
}
// 使用状态模式
const context = new Context();
context.request();
context.request();
context.request();
</script>
</body>
</html>