工厂模式
工厂模式提供了一种创建对象的最佳方式,在工厂模式中,我们创建对象时不会对客户端暴露创建逻辑,而是通过使用一个共同的接口来指向新创建的对象。
- 简单工厂模式
- 工厂方法模式
- 抽象工厂模式
优点:
- 解耦:将对象的创建与使用分离,使得系统更加灵活。
- 易于扩展:当需要增加新的咖啡类型时,只需增加新的实现类,并在工厂类中添加相应的逻辑即可,无需修改客户端代码。
缺点:
- 增加复杂度:当系统中存在大量的产品类时,工厂类的逻辑可能会变得非常复杂。
- 违反开闭原则:在简单工厂模式中,增加新的产品类时,通常需要修改工厂类,这违反了开闭原则(对扩展开放,对修改关闭)。
简单工厂模式
简化客户端代码,通过一个工厂类来创建对象。
场景复现
假设我们有一个咖啡店,它提供多种咖啡的制作。每种咖啡(如拿铁、卡布奇诺、美式等)的制作过程略有不同,但我们希望有一个统一的接口来订购咖啡,而不需要知道每种咖啡的具体制作过程。
抽象产品接口
咖啡接口:定义制作咖啡的方法
public interface Coffee{
void prepareRecipe();
}
具体产品
实现咖啡接口的具体咖啡类(如Espresso、Latte、Cappuccino等)
public class Espresso implements Coffee{
@Override
public void prepareRecipe(){
System.out.println("Preparing Espresso");
}
}
public class Latte implements Coffee {
@Override
public void prepareRecipe() {
System.out.println("Preparing Latte");
}
}
工厂类
咖啡工厂类:这个类根据传入的类型信息返回相应的咖啡对象
public class CoffeeFactory {
public static Coffee getCoffee(String type){
if(type == null){
return null;
}
if(type.equalsIgnoreCase("espresso")){
return new Espresso();
}else if(type.equalsIgnoreCase("latte")){
return new Latte();
}
return null;
}
}
测试方法
订购咖啡测试方法:
public static void main(String[] args) {
Coffee myCoffee = CoffeeFactory.getCoffee("latte");
if (myCoffee != null) {
myCoffee.prepareRecipe();
}
}
工厂方法模式
工厂方法模式
工厂方法模式与简单工厂模式相比,工厂方法模式提供了更高的灵活性和更好的扩展性。
定义:工厂方法模式定义了一个创建对象的接口,但允许子类决定实例化哪一个类。工厂方法让类的实例化推迟到子类。
目的
- 解耦:将对象的创建与使用对象的代码解耦。
- 扩展性:当需要添加新的产品时,只需要增加新的具体工厂类,而不需要修改已有的工厂接口或客户端代码。
- 遵循开闭原则:对扩展开放,对修改关闭。
结构
- 抽象工厂:定义一个用于创建产品的接口。
- 具体工厂:实现抽象工厂中的接口,完成具体产品的创建。
- 抽象产品:定义产品的规范,描述所有实例所共有的公共接口。
- 具体产品:由具体工厂创建的对象。
优点
- 易于扩展:当需要添加新的图形类型时,只需要增加一个新的具体工厂类即可,不需要修改已有的工厂接口或客户端代码。
- 解耦:客户端只依赖于抽象工厂接口,而不依赖于具体的工厂实现。
- 遵循开闭原则:对扩展开放,对修改关闭。
缺点
- 增加复杂性:对于每一种产品都需要一个具体的工厂类,增加了系统的复杂性。
- 多态性限制:如果需要创建的产品具有不同的接口,则不适合使用工厂方法模式。
应用场景
- 当系统中存在多个产品等级结构时:例如,不同的图形类。
- 当希望客户端独立于如何创建对象以及对象的实际实现时:例如,客户端只需要知道如何获取图形对象,而不关心具体的创建逻辑。
- 当一个类希望由它的子类来指定它所创建的对象时:例如,父类定义一个工厂方法,由子类实现具体的创建逻辑。
总结:工厂方法模式通过定义一个创建对象的接口,并让具体的子类决定实例化哪一个类,从而将对象的创建与使用对象的代码解耦。这种方式不仅提高了代码的可扩展性,而且遵循了开闭原则,使得系统更加灵活和易于维护
场景描述
创建一个图形绘制系统,支持圆形,原形,矩形和三角形。每种图形应该包含基础的绘图方法
抽象工厂接口
public interface ShapeFactory {
Shape getShape();
}
具体工厂
为上述图形(圆形,原形,矩形和三角形)提供具体的工厂类
public class CircleFactory implements ShapeFactory {
@Override
public Shape getShape() {
return new Circle();
}
}
public class RectangleFactory implements ShapeFactory {
@Override
public Shape getShape() {
return new Rectangle();
}
}
public class TriangleFactory implements ShapeFactory {
@Override
public Shape getShape() {
return new Triangle();
}
}
抽象产品
public interface Shape {
void draw();
}
具体产品
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("Drawing a circle.");
}
}
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Drawing a rectangle.");
}
}
public class Triangle implements Shape {
@Override
public void draw() {
System.out.println("Drawing a triangle.");
}
}
客户端测试
public class Client {
public static void main(String[] args) {
ShapeFactory circleFactory = new CircleFactory();
Shape circle = circleFactory.getShape();
circle.draw();
ShapeFactory rectangleFactory = new RectangleFactory();
Shape rectangle = rectangleFactory.getShape();
rectangle.draw();
ShapeFactory triangleFactory = new TriangleFactory();
Shape triangle = triangleFactory.getShape();
triangle.draw();
}
}
抽象工厂模式
抽象工厂模式,提供了一种创建一系列相关或依赖对象的接口,而无需指定它们具体的类。
创建一组相关的产品对象,确保它们协同工作 (如:电脑需要有外设:键盘+鼠标+音响 才能更好的协同工作)
结构:
- 抽象工厂:定义一个用于创建产品的几口。
- 具体工厂:实现抽象工厂中的接口,完成具体产品的创建。
- 抽象产品:定义产品的规范,描述所有实例共有的公共接口。
- 具体产品:由工厂创建的对象。
优点:
- 封装性:抽象工厂模式将产品族的创建封装在一个工厂类中,使得客户端不需要关心具体的创建逻辑。
- 易扩展:如果需要添加新的产品族(如 Linux 风格),只需添加一个新的具体工厂类即可。
- 一致性:保证同一产品族中的产品对象协同工作,避免了不同风格的产品混用带来的问题。
缺点:
- 增加复杂性:抽象工厂模式增加了系统的复杂性,因为需要定义更多的接口和类。
- 难以修改产品族:如果需要修改某个产品族中的产品,可能需要修改多个类。
- 违反开闭原则:如果需要添加新的产品类型(如新的控件),需要修改现有的工厂类。
应用场景
- 需要创建一系列相关产品:例如,创建不同风格的界面组件。
- 产品族中的产品需要协同工作:例如,不同风格的按钮和文本框需要一致的外观和行为。
总结:抽象工厂模式通过定义一个创建一系列相关或依赖对象的接口,使得客户端可以方便地创建一组相关的产品对象。这种方式使得系统更加模块化、易于扩展和维护。在实际应用中,抽象工厂模式特别适用于需要创建多个相关产品族的场景。
场景描述
如:QQ登录窗体,由文本输入框和按钮组合完成登录功能。对于mac,linux,win,移动端,qq的登录窗体可能展现风格是不同的或者相同的,但是基本都是由 按钮和输入框完成。此时就可以使用抽象工厂来完成。
抽象工厂
public interface GUIFactory {
Button createButton();
TextField createTextField();
}
具体工厂
// WindowsFactory
public class WindowsFactory implements GUIFactory {
@Override
public Button createButton() {
return new WindowsButton();
}
@Override
public TextField createTextField() {
return new WindowsTextField();
}
}
// MacFactory
public class MacFactory implements GUIFactory {
@Override
public Button createButton() {
return new MacButton();
}
@Override
public TextField createTextField() {
return new MacTextField();
}
}
抽象产品
public interface Button {
void paint();
}
public interface TextField {
void paint();
}
具体产品
public class WindowsButton implements Button {
@Override
public void paint() {
System.out.println("Painting a Windows button.");
}
}
public class MacButton implements Button {
@Override
public void paint() {
System.out.println("Painting a Mac button.");
}
}
public class WindowsTextField implements TextField {
@Override
public void paint() {
System.out.println("Painting a Windows text field.");
}
}
public class MacTextField implements TextField {
@Override
public void paint() {
System.out.println("Painting a Mac text field.");
}
}
客户端测试
public class Client {
public static void main(String[] args) {
// 使用 Windows 风格的工厂
GUIFactory windowsFactory = new WindowsFactory();
Button windowsButton = windowsFactory.createButton();
TextField windowsTextField = windowsFactory.createTextField();
windowsButton.paint();
windowsTextField.paint();
// 使用 Mac 风格的工厂
GUIFactory macFactory = new MacFactory();
Button macButton = macFactory.createButton();
TextField macTextField = macFactory.createTextField();
macButton.paint();
macTextField.paint();
}
}
三者的对比
简单工厂 vs
工厂方法 vs
抽象工厂:
- 扩展性
简单工厂模式:扩展性较差,因为需要修改工厂类来添加新的产品类型。
工厂方法模式:扩展性较好,通过新增具体工厂类来添加新产品类型。
抽象工厂模式:扩展性好,通过新增具体工厂类来添加新产品族,但修改产品族较难。 - 解耦
简单工厂模式:客户端依赖于具体的工厂类。
工厂方法模式:客户端依赖于抽象工厂接口。
抽象工厂模式:客户端依赖于抽象工厂接口。 - 支持继承
简单工厂模式:不支持继承。
工厂方法模式:支持继承。
抽象工厂模式:支持继承。 - 创建对象的类型
简单工厂模式:创建单个对象。
工厂方法模式:创建单个对象。
抽象工厂模式:创建一系列相关对象。 - 适用场景
简单工厂模式:适用于创建的对象较少,且不经常需要添加新类型的情况。
工厂方法模式:适用于需要创建多个相关产品,并且未来可能需要添加新产品类型的情况。
抽象工厂模式:适用于需要创建多个相关产品族,并且未来可能需要添加新产品族的情况。