简单工厂方法模式是一种创建型设计模式,它提供了一个统一的接口来创建对象,但隐藏了对象的具体实现细节。简单工厂模式通过一个工厂类,根据不同的参数来创建不同的产品对象,使得客户端代码与具体产品的创建过程解耦。
简单工厂模式包含以下几个核心组件:
简单工厂模式的优点包括:
以下是一个使用简单工厂模式创建不同类型动物的示例:
```javascript
// 抽象产品类 - 动物
class Animal {
constructor(name) {
this.name = name;
}
sound() {
// 抽象方法,具体的动物类需要实现该方法
}
}
// 具体产品类 - 狗
class Dog extends Animal {
sound() {
return "汪汪汪!";
}
}
// 具体产品类 - 猫
class Cat extends Animal {
sound() {
return "喵喵喵!";
}
}
// 简单工厂类
class AnimalFactory {
createAnimal(type, name) {
switch (type) {
case "dog":
return new Dog(name);
case "cat":
return new Cat(name);
default:
throw new Error("Invalid animal type.");
}
}
}
// 使用简单工厂创建对象
const factory = new AnimalFactory();
const dog = factory.createAnimal("dog", "旺财");
const cat = factory.createAnimal("cat", "小花");
console.log(dog.sound()); // 输出:汪汪汪!
console.log(cat.sound()); // 输出:喵喵喵!
在上述示例中,我们定义了一个抽象产品类 Animal
,它有一个抽象方法 sound()
。然后,我们创建了两个具体产品类 Dog
和 Cat
,它们分别继承自 Animal
并实现了 sound()
方法。
接下来,我们定义了一个简单工厂类 AnimalFactory
,它有一个 createAnimal()
方法,根据传入的类型参数来创建不同的动物对象。
最后,我们使用简单工厂类创建了一个 AnimalFactory
实例,并使用 createAnimal()
方法创建了一个狗对象和一个猫对象。通过调用对象的 sound()
方法,我们可以分别输出它们的声音。
这个例子展示了如何使用简单工厂模式在JavaScript中创建不同类型的对象,通过工厂类将对象的创建过程与客户端代码解耦。
简单工厂模式适用于以下情况:
工厂方法模式(Factory Method Pattern)是一种创建型设计模式,它通过定义一个创建对象的接口,但将具体对象的创建延迟到子类中实现。工厂方法模式使得一个类的实例化延迟到其子类,从而实现了对象的创建与使用的解耦。
工厂方法模式包含以下几个核心组件:
抽象产品类(Product):定义产品的共同接口,所有具体产品类都必须实现这个接口。
具体产品类(Concrete Product):实现抽象产品类接口的具体产品。
抽象工厂类(Factory):定义创建产品的抽象方法,由子类来实现具体的产品创建。
具体工厂类(Concrete Factory):实现抽象工厂类的抽象方法,负责创建具体的产品对象。
工厂方法模式的工作流程如下:
客户端通过调用具体工厂类的方法来创建产品对象。
具体工厂类根据需要创建相应的具体产品对象,并返回给客户端。
客户端通过产品的共同接口来使用具体产品对象,而不需要关心具体产品的创建过程。
工厂方法模式与简单工厂模式的区别在于,工厂方法模式将对象的创建延迟到子类中实现,每个具体产品都有对应的具体工厂类,而简单工厂模式通过一个工厂类来创建所有的产品对象。
符合开闭原则:当需要新增加一种产品时,只需要创建相应的具体产品类和具体工厂类,而不需要修改已有的代码。
客户端与具体产品解耦:客户端只需要与抽象工厂和抽象产品进行交互,不需要直接依赖具体产品类,降低了客户端的复杂性。
支持多态性:每个具体工厂类都可以返回不同类型的具体产品,通过多态性来实现不同产品的创建和使用。
类的个数增加:每个具体产品都需要对应一个具体工厂类,导致类的个数增加。
增加系统的抽象性和理解难度:工厂方法模式引入了抽象工厂和抽象产品的概念,增加了系统的抽象性和理解难度。
// 抽象产品类 - 按钮
class Button {
render() {
// 抽象方法,具体的按钮类需要实现该方法
}
}
// 具体产品类 - 圆形按钮
class CircleButton extends Button {
render() {
console.log("渲染圆形按钮");
}
}
// 具体产品类 - 方形按钮
class SquareButton extends Button {
render() {
console.log("渲染方形按钮");
}
}
// 抽象工厂类 - 按钮工厂
class ButtonFactory {
createButton() {
// 抽象方法,由具体的工厂类来实现该方法
}
}
// 具体工厂类 - 圆形按钮工厂
class CircleButtonFactory extends ButtonFactory {
createButton() {
return new CircleButton();
}
}
// 具体工厂类 - 方形按钮工厂
class SquareButtonFactory extends ButtonFactory {
createButton() {
return new SquareButton();
}
}
// 使用工厂方法创建对象
function createButton(factory) {
const button = factory.createButton();
button.render();
}
// 创建圆形按钮工厂
const circleButtonFactory = new CircleButtonFactory();
createButton(circleButtonFactory); // 输出:渲染圆形按钮
// 创建方形按钮工厂
const squareButtonFactory = new SquareButtonFactory();
createButton(squareButtonFactory); // 输出:渲染方形按钮
工厂方法模式适用于以下情况:
需要创建的对象种类较多:当需要创建的对象种类较多且相对稳定时,可以使用工厂方法模式。
客户端不关心对象的具体实现:客户端只需要使用对象的共同接口,对于具体实现不关心时,可以使用工厂方法模式。
抽象工厂模式是一种创建型设计模式,用于创建一系列相关或相互依赖的对象。它提供了一种方式来封装对象的创建过程,使得客户端代码与具体的产品类解耦。
在抽象工厂模式中,有以下几个核心角色:
抽象工厂(Abstract Factory):定义了创建一系列相关产品对象的接口。它声明了一组用于创建不同产品对象的抽象方法。
具体工厂(Concrete Factory):实现了抽象工厂接口,负责创建一系列具体的产品对象。每个具体工厂类对应一族产品。
抽象产品(Abstract Product):定义了一类产品对象的接口。它可以是一个具体产品类的抽象,也可以是一个接口。
具体产品(Concrete Product):实现了抽象产品接口,具体工厂类创建的产品就是具体产品的实例。
使用抽象工厂模式的主要步骤如下:
定义抽象产品接口:创建一系列产品对象所共有的接口,并声明产品对象的方法。
定义抽象工厂接口:声明用于创建产品对象的抽象方法。
实现具体产品类:实现抽象产品接口,定义具体产品的具体行为。
实现具体工厂类:实现抽象工厂接口,实现抽象方法来创建具体产品对象。
在客户端代码中使用抽象工厂:客户端通过抽象工厂接口来创建产品对象,而不直接依赖具体产品类。这样可以使客户端与具体产品类解耦,增加了灵活性和可扩展性。
提供了一种封装对象创建过程的方式,使得客户端代码与具体产品类解耦,增加了灵活性和可扩展性。
支持产品族的扩展,即可以创建一系列相关的产品对象。
符合开闭原则,当需要增加新的产品族时,只需要添加相应的具体工厂类和具体产品类,而无需修改已有代码。
增加新的产品等级结构(即新的抽象产品类)比较困难,需要修改抽象工厂接口和所有的具体工厂类。
当产品族中的产品等级结构发生变化时,需要修改抽象工厂接口和所有的具体工厂类。
// 抽象产品类 - 按钮
class Button {
render() {
// 抽象方法,具体的按钮类需要实现该方法
}
}
// 具体产品类 - 圆形按钮
class CircleButton extends Button {
render() {
console.log("渲染圆形按钮");
}
}
// 具体产品类 - 方形按钮
class SquareButton extends Button {
render() {
console.log("渲染方形按钮");
}
}
// 抽象产品类 - 文本框
class TextBox {
render() {
// 抽象方法,具体的文本框类需要实现该方法
}
}
// 具体产品类 - 圆形文本框
class CircleTextBox extends TextBox {
render() {
console.log("渲染圆形文本框");
}
}
// 具体产品类 - 方形文本框
class SquareTextBox extends TextBox {
render() {
console.log("渲染方形文本框");
}
}
// 抽象工厂类 - UI工厂
class UIFactory {
createButton() {
// 抽象方法,由具体的工厂类来实现该方法
}
createTextBox() {
// 抽象方法,由具体的工厂类来实现该方法
}
}
// 具体工厂类 - 圆形UI工厂
class CircleUIFactory extends UIFactory {
createButton() {
return new CircleButton();
}
createTextBox() {
return new CircleTextBox();
}
}
// 具体工厂类 - 方形UI工厂
class SquareUIFactory extends UIFactory {
createButton() {
return new SquareButton();
}
createTextBox() {
return new SquareTextBox();
}
}
// 使用抽象工厂创建对象
function createUI(factory) {
const button = factory.createButton();
const textBox = factory.createTextBox();
button.render();
textBox.render();
}
// 创建圆形UI工厂
const circleUIFactory = new CircleUIFactory();
createUI(circleUIFactory);
// 输出:
// 渲染圆形按钮
// 渲染圆形文本框
// 创建方形UI工厂
const squareUIFactory = new SquareUIFactory();
createUI(squareUIFactory);
// 输出:
// 渲染方形按钮
// 渲染方形文本框
抽象工厂模式适用于需要创建一系列相关产品对象,并且需要增加新的产品族时。它提供了一种灵活的方式来封装对象的创建过程,使得客户端代码与具体产品类解耦。
选择适合的模式取决于具体的需求和设计考虑。如果只有少量的产品需要创建,并且创建逻辑简单,可以使用简单工厂模式;如果有多个产品需要创建,并且每个产品都有对应的工厂类,可以使用工厂方法模式;如果需要创建一系列相关产品对象,并且支持产品族的扩展,可以使用抽象工厂模式。
单例模式(Singleton Pattern)是一种常用的软件设计模式。在这种模式中,一个类只允许创建一个对象(或实例),即一个类只有一个实例存在。单例模式确保全局只有一个对象可用,并提供一个访问它的全局访问点。
单例模式可以通过不同的方式实现,例如:
单例模式适用于以下情况:
以下是一个 JavaScript 中单例模式的简单实现(懒汉式):
class Singleton {
constructor() {
if (!Singleton.instance) {
Singleton.instance = this;
}
return Singleton.instance;
}
someMethod() {
// 方法实现
}
}
// 使用
const instance1 = new Singleton();
const instance2 = new Singleton();
console.log(instance1 === instance2); // true
在这个例子中,Singleton
类使用了懒汉式实现。当尝试通过 new Singleton()
创建一个新的实例时,类首先检查它是否已经有一个实例存在。如果存在,它就返回那个实例,否则,它会创建一个新实例。
观察者模式(Observer Pattern)是一种行为设计模式,允许对象(称为观察者)订阅另一个对象(称为主题),以便在主题状态发生变化时得到通知。这种模式常用于实现事件处理系统。
观察者模式适用于以下情况:
class Subject {
constructor() {
this.observers = [];
}
subscribe(observer) {
this.observers.push(observer);
}
unsubscribe(observer) {
this.observers = this.observers.filter(obs => obs !== observer);
}
notify(data) {
this.observers.forEach(observer => observer.update(data));
}
}
class Observer {
constructor(name) {
this.name = name;
}
update(data) {
console.log(`${this.name} received data: ${data}`);
}
}
// 使用
const subject = new Subject();
const observer1 = new Observer("Observer 1");
const observer2 = new Observer("Observer 2");
subject.subscribe(observer1);
subject.subscribe(observer2);
subject.notify("Hello World!"); // Both observers receive the notification
subject.unsubscribe(observer1);
subject.notify("Second message"); // Only Observer 2 receives the notification
在这个例子中,Subject
类管理观察者并提供订阅(subscribe
)和取消订阅(unsubscribe
)的功能。当调用 notify
方法时,所有订阅的观察者都会收到通知。每个 Observer
类实例都可以接收到这些通知。这样,我们可以动态地添加、移除或通知观察者,而主题对象无需了解观察者的具体实现。
适配器模式(Adapter Pattern)是一种结构型设计模式,它允许不兼容的接口之间进行交互。适配器模式通过创建一个中间层,使得原本由于接口不兼容而不能一起工作的类可以协同工作。
适配器模式适用于以下情况:
假设有一个旧的电子邮件发送系统(OldEmailSender
),它的接口与当前系统不兼容。我们需要使用适配器使其可以在新系统中使用。
// 被适配者
class OldEmailSender {
send(email, content) {
console.log(`Sending '${content}' to '${email}' via OldEmailSender`);
}
}
// 目标接口
class NewEmailService {
sendEmail(email, content) {
throw new Error("This method needs to be implemented!");
}
}
// 适配器
class EmailAdapter extends NewEmailService {
constructor(oldEmailSender) {
super();
this.oldEmailSender = oldEmailSender;
}
sendEmail(email, content) {
this.oldEmailSender.send(email, content);
}
}
// 客户端代码
const oldEmailSender = new OldEmailSender();
const emailAdapter = new EmailAdapter(oldEmailSender);
emailAdapter.sendEmail("[email protected]", "Hello, this is a test email!");
在这个例子中,OldEmailSender
是一个已经存在的类,但它的接口与新系统中期望的接口不匹配。EmailAdapter
是一个适配器,它实现了新的邮件服务接口并在内部使用 OldEmailSender
。客户端代码可以透明地使用 EmailAdapter
发送电子邮件,无需关心其内部是如何使用 OldEmailSender
的。这就是适配器模式的实用之处。
职责链模式(Chain of Responsibility Pattern)是一种行为型设计模式,它使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。在这个模式中,请求沿着一条链传递,直到一个对象处理它为止。
职责链模式适用于以下情况:
// 处理器接口
class Handler {
constructor() {
this.nextHandler = null;
}
setNextHandler(handler) {
this.nextHandler = handler;
}
handleRequest(request) {
if (this.nextHandler) {
this.nextHandler.handleRequest(request);
}
}
}
// 具体处理器
class ConcreteHandler1 extends Handler {
handleRequest(request) {
if (request === 'R1') {
console.log('ConcreteHandler1 handled the request');
} else {
super.handleRequest(request);
}
}
}
class ConcreteHandler2 extends Handler {
handleRequest(request) {
if (request === 'R2') {
console.log('ConcreteHandler2 handled the request');
} else {
super.handleRequest(request);
}
}
}
// 客户端代码
const handler1 = new ConcreteHandler1();
const handler2 = new ConcreteHandler2();
handler1.setNextHandler(handler2);
handler1.handleRequest('R2'); // 输出:ConcreteHandler2 handled the request
在这个例子中,两个具体的处理器(ConcreteHandler1
和 ConcreteHandler2
)被创建,并形成一条链。当请求'R2'
到达时,它首先被ConcreteHandler1
接收,但因为ConcreteHandler1
不能处理,所以它将请求传递给链上的下一个处理器ConcreteHandler2
,后者处理这个请求。通过这种方式,职责链模式允许请求在多个对象之间传递,直到找到一个能够处理它的对象为止。