简单工厂模式(Simple Factory Pattern)
简单工厂方法模式是一种创建型设计模式,它提供了一个统一的接口来创建对象,但隐藏了对象的具体实现细节。简单工厂模式通过一个工厂类,根据不同的参数来创建不同的产品对象,使得客户端代码与具体产品的创建过程解耦。
简单工厂模式包含以下几个核心组件:
- 工厂类(Factory):负责创建产品对象的类。它通常包含一个静态方法,根据传入的参数来创建不同的产品对象。
- 抽象产品类(Product):定义产品的共同接口,所有具体产品类都必须实现这个接口。
- 具体产品类(Concrete Product):实现抽象产品类接口的具体产品。工厂类根据不同的参数来创建不同的具体产品对象。
优点
简单工厂模式的优点包括:
- 客户端与具体产品解耦:客户端只需要与工厂类进行交互,不需要直接依赖具体产品类,降低了客户端的复杂性。
- 隐藏对象创建细节:客户端不需要关心具体产品的创建过程,只需要关心如何使用产品。
- 简化对象创建:通过工厂类集中管理对象的创建,可以提供统一的创建方式和参数验证,简化了对象的创建过程。
缺点
- 不符合开闭原则:当需要新增加一种产品时,需要修改工厂类的代码,违反了开闭原则。
- 工厂类职责过重:随着产品种类的增多,工厂类的职责会变得越来越重,可能会导致工厂类的代码臃肿。
- 不易扩展:由于工厂类集中了所有产品的创建逻辑,当需要添加新的产品时,需要修改工厂类的代码,扩展性较差。
例子
以下是一个使用简单工厂模式创建不同类型动物的示例:```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);
// 输出:
// 渲染方形按钮
// 渲染方形文本框
总结
抽象工厂模式适用于需要创建一系列相关产品对象,并且需要增加新的产品族时。它提供了一种灵活的方式来封装对象的创建过程,使得客户端代码与具体产品类解耦。
三者对比
- 简单工厂模式适用于对象的创建逻辑相对简单的情况,但不符合开闭原则。
- 工厂方法模式适用于需要创建单个产品对象的情况,每个产品有对应的具体工厂类。
- 抽象工厂模式适用于需要创建一系列相关产品对象的情况,支持产品族的扩展,但增加了系统的抽象性和理解难度。
选择适合的模式取决于具体的需求和设计考虑。如果只有少量的产品需要创建,并且创建逻辑简单,可以使用简单工厂模式;如果有多个产品需要创建,并且每个产品都有对应的工厂类,可以使用工厂方法模式;如果需要创建一系列相关产品对象,并且支持产品族的扩展,可以使用抽象工厂模式。