设计模式之工厂模式详解
模式的分类
创建模式 提供了创建对象的机制 可以提高灵活性和现有代码的重要性
结构模式 解释了对象与类组装更大的结构 同时又保持结构的灵活性和效率
行为模式 负责相互之间的沟通以及对象有效的责任分配
工厂模式
工厂模式 如果比如物流业务,只限于卡车运输,那么直开发卡车接口,只用卡车类,再相加轮船运输,就会耦合度非常大,代码改起来非常麻烦。所以要用到工厂模式
如果说轮船跟卡车都要用到Transport类,而Transport接口有一个deliver()交付方法,卡车运输走卡车运输交付,轮船运输走轮船运输交付,返回不同的对象,简单明了
这样一个流程图,调用工厂方法,简称客户端的代码,不用了解各个返回对象的差别,客户端将所有Transport接口产品统称为抽象类(抽象的运输),客户端知道所有的运输方法都有交付的方法,但是并不用关心具体的实现方法。
1.Product产品接口,将会对接口进行声明,对于所有的创建者以及子类的构建,接口都是完全通用的
2.ConcreteProduct是产品接口不同的实现
3.Creator创建者,虽然是创建者类但是是声明返回产品对象工厂方法,方法类型必须与产品的接口的方法相匹配,就是把产品接口的不同实现拆分开来。可以将工厂方法声明为抽象方法,强制每个不同的类以不同的方式实现该方法。
工厂方法模式适合应用的场景
1.如果无法知道对象确切类别以及其依赖关系的时候,可以使用工厂方法。
2.工厂方法将创建产品的代码与实际使用的产品代码分离,从而不能影响其他的代码情况下扩展产品创建部分代码。
3.假如要添加一个新的产品,只需要开发新的创建子类,然后重写其中工厂方法就行了。
4.如果用户希望扩展软件库或框架的组件,可以使用工厂方法。
4.1比如你要用一个开源的UI框架编写应用,你要用到圆形按钮,但是之后长方形按钮,这你就需要使用圆形按钮继承标准的按钮类,但是你要告诉这个UI框架UIFramework类使用新的子类按钮代替默认按钮。
为了实现功能,可以根据基础框架类子类圆形按钮UIWithRoundButtons,并重写创建按钮方法,基础类中返回按钮对象,现在新开发的对象,现在可以使用新的圆形按钮类代替ui框架类。
5.如果希望复用现有的对象来节省系统资源,而不是每次都会重新创建对象,可使用工厂方法。
工厂模式的优点以及缺点
可以避免创建者与具体产品之间的紧密耦合。
单一的职责,可以将产品创建代码放在程序的单一设置,从而更容易维护。
开闭原则,无需更改现有客户端的代码,就可以开发新的具体产品类型。
缺点:工厂模式需要引进许多新的子类,代码会变的复杂,最好的情况是该将模式引入创建者类的现有的层次结构中。
与其他模式的关系
1.再许多设计中工厂模式较为简单,随后演化为抽象工厂模式,原型模式或生成器模式更加灵活但是更加复杂。
2.抽象工厂模式基于一组工厂模式,也可以使用原型模式来生成这些类的方法。
3.可以使用工厂模式和迭代器模式让子类集合返回不同类型的迭代器,并使迭代器与集合相匹配。
4.原型模式不基于继承,因此没有继承的缺点,但是原型模式需要复杂的初始化,工厂模式基于继承所有不需要初始化。
5.工厂模式是模板方法模式的一种特殊形式,同时,工厂模式可以作为一个大型模板方法中的一个步骤。
代码示例
buttons/Button.java: 通用产品接口
package refactoring_guru.factory_method.example.buttons;
/**
* Common interface for all buttons.
*/
public interface Button {
void render();
void onClick();
}
buttons/HtmlButton.java: 具体产品
package refactoring_guru.factory_method.example.buttons;
/**
* HTML button implementation.
*/
public class HtmlButton implements Button {
public void render() {
System.out.println("<button>Test Button</button>");
onClick();
}
public void onClick() {
System.out.println("Click! Button says - 'Hello World!'");
}
}
buttons/WindowsButton.java: 另一个具体产品
package refactoring_guru.factory_method.example.buttons;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
/**
* Windows button implementation.
*/
public class WindowsButton implements Button {
JPanel panel = new JPanel();
JFrame frame = new JFrame();
JButton button;
public void render() {
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel label = new JLabel("Hello World!");
label.setOpaque(true);
label.setBackground(new Color(235, 233, 126));
label.setFont(new Font("Dialog", Font.BOLD, 44));
label.setHorizontalAlignment(SwingConstants.CENTER);
panel.setLayout(new FlowLayout(FlowLayout.CENTER));
frame.getContentPane().add(panel);
panel.add(label);
onClick();
panel.add(button);
frame.setSize(320, 200);
frame.setVisible(true);
onClick();
}
public void onClick() {
button = new JButton("Exit");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
frame.setVisible(false);
System.exit(0);
}
});
}
}
factory/Dialog.java: 基础创建者
package refactoring_guru.factory_method.example.factory;
import refactoring_guru.factory_method.example.buttons.Button;
/**
* Base factory class. Note that "factory" is merely a role for the class. It
* should have some core business logic which needs different products to be
* created.
*/
public abstract class Dialog {
public void renderWindow() {
// ... other code ...
Button okButton = createButton();
okButton.render();
}
/**
* Subclasses will override this method in order to create specific button
* objects.
*/
public abstract Button createButton();
}
factory/HtmlDialog.java: 具体创建者
package refactoring_guru.factory_method.example.factory;
import refactoring_guru.factory_method.example.buttons.Button;
import refactoring_guru.factory_method.example.buttons.HtmlButton;
/**
* HTML Dialog will produce HTML buttons.
*/
public class HtmlDialog extends Dialog {
@Override
public Button createButton() {
return new HtmlButton();
}
}
factory/WindowsDialog.java: 另一个具体创建者
package refactoring_guru.factory_method.example.factory;
import refactoring_guru.factory_method.example.buttons.Button;
import refactoring_guru.factory_method.example.buttons.WindowsButton;
/**
* Windows Dialog will produce Windows buttons.
*/
public class WindowsDialog extends Dialog {
@Override
public Button createButton() {
return new WindowsButton();
}
}
Demo.java: 客户端代码
package refactoring_guru.factory_method.example;
import refactoring_guru.factory_method.example.factory.Dialog;
import refactoring_guru.factory_method.example.factory.HtmlDialog;
import refactoring_guru.factory_method.example.factory.WindowsDialog;
/**
* Demo class. Everything comes together here.
*/
public class Demo {
private static Dialog dialog;
public static void main(String[] args) {
configure();
runBusinessLogic();
}
/**
* The concrete factory is usually chosen depending on configuration or
* environment options.
*/
static void configure() {
if (System.getProperty("os.name").equals("Windows 10")) {
dialog = new WindowsDialog();
} else {
dialog = new HtmlDialog();
}
}
/**
* All of the client code should work with factories and products through
* abstract interfaces. This way it does not care which factory it works
* with and what kind of product it returns.
*/
static void runBusinessLogic() {
dialog.renderWindow();
}
}
OutputDemo.txt: 执行结果 (HtmlDialog)
<button>Test Button</button>
Click! Button says - 'Hello World!'
OutputDemo.png: 执行结果 (WindowsDialog)
刚刚学习完分享一下经验,也对自己做一个记录,一起加油,这里是不会写代码的安慕希。