每日一言 没有什么是完美的,这个世界并不完美,所以才显得美丽。——《钢之炼金术师》
什么是工厂方法(Factory Method) Java中的工厂方法是一种创建对象的设计模式,属于创建模式 之一。工厂方法通过定义一个创建对象的接口,让子类决定实例化哪一个类。这样做的好处是将对象的创建过程封装起来,使得客户端代码不需要知道具体的类,而是通过工厂方法来获取所需的对象。
主要特点:
定义接口 :工厂方法定义了创建对象的接口,但将实际创建对象的工作交给子类去完成。
子类决定对象 :通过继承工厂类并实现工厂方法,子类可以决定具体创建哪个类的实例。
解耦对象创建 :客户端不需要关心具体的类,只需要通过工厂方法来创建对象,从而实现了代码的解耦和扩展性。
如何写好一个工厂方法 第一步:定义产品的抽象接口或抽象类 产品是由工厂创建的对象(实例),并且他们都实现了同一个抽象接口或父类。这个抽象类中应该包含所有产品至少应该实现的接口。
📌 举个例子:
假设你有一个发送消息的系统,支持多种通知方式:
通知方式
类名
属于“产品”吗?
发送邮件
EmailNotification
✅ 是产品
发送短信
SMSNotification
✅ 是产品
发送微信
WeChatNotification
✅ 是产品
它们都有一个共同的“父类”或“接口”:
1 2 3 interface Notification { void send (String message) ; }
第二步:创建多个具体的产品实现类 这些类是实际的产品。也就是说我们需要实现我们所需要的每个产品的具体实现。
1 2 3 4 5 6 7 8 9 10 11 12 class EmailNotification implements Notification { public void send (String message) { System.out.println("发送邮件: " + message); } }class SMSNotification implements Notification { public void send (String message) { System.out.println("发送短信: " + message); } }
第三步:定义一个抽象工厂或接口 抽象工厂描述了创建产品的方法:
1 2 3 abstract class NotificationFactory { public abstract Notification createNotification () ; }
也可以是接口:
1 2 3 interface NotificationFactory { Notification createNotification () ; }
第四步:实现具体的工厂子类 每个子类负责创建一个具体的产品:
1 2 3 4 5 6 7 8 9 10 11 class EmailFactory extends NotificationFactory { public Notification createNotification () { return new EmailNotification (); } }class SMSFactory extends NotificationFactory { public Notification createNotification () { return new SMSNotification (); } }
第五步:添加一个工厂选择器(用于根据不同类型返回不同工厂) 1 2 3 4 5 6 7 8 9 10 NotificationFactoryProvider { public static NotificationFactory getFactory (String type) { switch (type.toLowerCase()) { case "email" : return new EmailFactory (); case "sms" : return new SMSFactory (); default : throw new IllegalArgumentException ("未知通知类型" ); } } }
第六步:客户端使用工厂选择器获取对象 1 2 3 4 5 6 7 8 public class Main { public static void main (String[] args) { NotificationFactory factory = NotificationFactoryProvider.getFactory("email" ); Notification notification = factory.createNotification(); notification.send("Hello, this is a test email!" ); } }
充分运用了多态的特性,当我们提前不知道需要那种通知方式时,通过使用工厂方法,在运行环境中动态调节我们生产的产品。
易扩展性 接下来我们继续通过这个例子体现工厂方法的易扩展性:
新增微信通知 工厂方法的生产方式在增加类型时,只动类,不懂客户端。即不需要修改Main函数中的内容。
我们先新增微信通知这个产品:
1 2 3 4 5 class WeChatNotification implements Notification { public void send (String message) { System.out.println("发送微信: " + message); } }
然后增加微信类的创建工厂:
1 2 3 4 5 class WeChatFactory extends NotificationFactory { public Notification createNotification () { return new WechatNotification (); } }
然后我们在工厂选择器中增加微信选项:
1 2 3 4 5 6 7 8 9 10 11 NotificationFactoryProvider { public static NotificationFactory getFactory (String type) { switch (type.toLowerCase()) { case "email" : return new EmailFactory (); case "sms" : return new SMSFactory (); case "wechat" : return new WeChatFactory ; default : throw new IllegalArgumentException ("未知通知类型" ); } } }
这样当客户端接收到字段wechat时,就会生成微信工厂,并生成微信产品。
简单工厂 对于上面的例子,似乎并不能很好的利用到工厂方法的特性,反而让程序过度封装显得冗杂。因此我们引入简单工厂,作为在相对简单的情况中使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 interface Notification { void send (String message) ; }class EmailNotification implements Notification { public void send (String message) { System.out.println("发送邮件: " + message); } }class SMSNotification implements Notification { public void send (String message) { System.out.println("发送短信: " + message); } }public class Main { public static void main (String[] args) { String type = "email" ; Notification notification = createNotification(type); notification.send("Hello, this is a test message!" ); } public static Notification createNotification (String type) { switch (type) { case "email" : return new EmailNotification (); case "sms" : return new SMSNotification (); default : throw new IllegalArgumentException ("Unknown notification type: " + type); } } }
省去了给每个商品创建工厂的步骤,使用一个大工厂直接生成对应商品。
抽象工厂(Abstract Factroy) 抽象工厂是工厂方法的升级版,使用于一组 产品的创建。
跨平台的GUI框架 如果我们想要开发一个跨平台的GUI框架,可以生成:
由于Windows系统和Mac系统UI风格不一致,你希望:
在Window系统下使用Windows风格组件
在Mac系统下使用Mac风格的组件
第一步:抽象产品族 我们给每一个产品创建一个接口:
1 2 3 4 5 6 7 8 9 10 interface Button { void render () ; }interface Textbox { void render () ; }
第二步:具体产品实现(Mac和Windows两种风格) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class WindowsButton implements Button { public void render () { System.out.println("渲染 Windows 风格按钮" ); } }class WindowsTextbox implements Textbox { public void render () { System.out.println("渲染 Windows 风格文本框" ); } }class MacButton implements Button { public void render () { System.out.println("渲染 Mac 风格按钮" ); } }class MacTextbox implements Textbox { public void render () { System.out.println("渲染 Mac 风格文本框" ); } }
第三步:抽象工厂接口 1 2 3 4 interface GUIFactory { Button createButton () ; Textbox createTextbox () ; }
第四步:具体工厂类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class WindowsFactory implements GUIFactory { public Button createButton () { return new WindowsButton (); } public Textbox createTextbox () { return new WindowsTextbox (); } }class MacFactory implements GUIFactory { public Button createButton () { return new MacButton (); } public Textbox createTextbox () { return new MacTextbox (); } }
第五步:客户端使用(不关心具体产品是哪一套) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class Main { public static void main (String[] args) { GUIFactory factory = getFactory("mac" ); Button button = factory.createButton(); Textbox textbox = factory.createTextbox(); button.render(); textbox.render(); } public static GUIFactory getFactory (String type) { if (type.equalsIgnoreCase("windows" )) { return new WindowsFactory (); } else if (type.equalsIgnoreCase("mac" )) { return new MacFactory (); } else { throw new IllegalArgumentException ("不支持的类型" ); } } }