Factory Method Pattern.
别名:虚拟构造器( Virtual Constructor)
定义
定义一个创建对象的接口,让子类决定实例化哪一个类,将类的实例化推迟到子类中进行。
应用场景
1.无法预知确切的类型及其依赖关系
工厂方法将创建产品的代码与实际使用产品的代码分离,则能在不影响其他代码的情况下扩展产品的创建部分代码。「 eg: 如果需要向应用添加一种新产品,则只需创建新的创建者子类,并重写该工厂方法即可 」
2.扩展 软件库 或 框架 的内部组件
3.通过复用现有对象来节省系统资源
实现方法
1.让所有产品都遵循同一接口。该接口含有对所有产品都有意义的方法
2.在创建类中添加一个空的工厂方法。该方法的返回类型和遵循通用的产品接口保持一致
3.为工厂方法中的每个产品编写一个建造者子类,并且在子类重写工厂方法。将相关创建的代码放入工厂方法中
4.当产品类型过多时,便没必要每个都创建创建者子类,而可以复用基类的控制参数
5.当基础工厂方法中已经没有任何代码,则可以转变为抽象类。若还有其它语句,则可以设置为该方法的默认行为
优缺点
优点:
1.避免创建者和具体产品的紧密耦合
2.单一职责原则。将产品的创建代码放在程序的单一位置上,从而使代码更易维护
3.开闭原则。增加新产品时,不需改变原有代码,只需引入新的产品及其创建者
缺点:
1.需要大量的子类,会使代码变得复杂。【最好的情况是将该模式引入创建者类的现有层次结构中】
结构
UML图
classDiagram
Creator<|--ConcreteCreatorA
Creator<|--ConcreteCreatorB
Product<..Creator
Product<|..ConcreteProductA
Product<|..ConcreteProductB
class Creator{
....
+someOperation()
+createProduct() Product
}
参与者
-
产品 ( Product ): 对接口进行声明【由建造者及其子类构建的对象】 -
具体产品 ( Concrete Products ):是产品接口的不同实现 -
创建者 ( Creator ):类声明 返回产品对象的工厂方法。该方法的返回类型必须与产品接口相匹配。【主要职责不是创建产品。通常包含一些与产品相关的核心业务逻辑。主要是将这些逻辑从具体产品中分离出来】 -
具体创建者 ( Concrete Creators ):重写声明的基础方法,使其返回不同类型的产品。【不仅可以是创建新的实例,还可以是返回缓存、对象池或其他来源的已有对象】
通用写法
public abstract class Product {
void show(){};
}
public class ConcreteProductA extends Product{
@Override
void show() {
System.out.println("this is ProductA");
}
}
public class ConcreteProductB extends Product{
@Override
void show() {
System.out.println("this is ProductB");
}
}
public interface Creator {
Product createProduct();
}
public class ConcreteCreatorA implements Creator{
@Override
public Product createProduct() {
return new ConcreteProductA();
}
}
public class ConcreteCreatorB implements Creator{
@Override
public Product createProduct() {
return new ConcreteProductB();
}
}
public class Client {
public static void main(String[] args) {
Creator creator = new ConcreteCreatorA();
creator.createProduct().show();
creator = new ConcreteCreatorB();
creator.createProduct().show();
}
}
案例
1.生成跨平台的 GUI 元素
不同类型的对话框需要其各自类型的元素。因此我们需要对每个对话框类型创建子类并重写其工厂方法
按钮类
public interface Button {
void render();
void onClick();
}
public class HtmlButton implements Button{
@Override
public void render() {
System.out.println("<button>HTML Button</button>");
}
@Override
public void onClick() {
System.out.println("Click ==> 'HEELO WORLD'");
}
}
public class WindowButton implements Button{
JPanel panel = new JPanel();
JFrame frame = new JFrame();
JButton button;
@Override
public void render() {
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel label = new JLabel("HELLO");
label.setOpaque(true);
label.setBackground(new Color(250,250,0));
label.setHorizontalAlignment(SwingConstants.CENTER);
label.setLayout(new FlowLayout(FlowLayout.CENTER));
frame.getContentPane().add(panel);
panel.add(label);
onClick();
panel.add(button);
frame.setSize(320,200);
frame.setVisible(true);
onClick();
}
@Override
public void onClick() {
button = new JButton("Exit");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
frame.setVisible(false);
System.exit(0);
}
});
}
}
创建者类
public abstract class Dialog {
public void renderWindow(){
Button okButton = createButton();
okButton.render();
}
public abstract Button createButton();
}
public class HtmlDialog extends Dialog{
@Override
public Button createButton() {
return new HtmlButton();
}
}
public class WindowDialog extends Dialog{
@Override
public Button createButton() {
return new WindowButton();
}
}
Client
public class Client {
private static Dialog dialog;
public static void main(String[] args) {
configure();
runBusinessLogic();
}
static void configure(){
String type = "window";
if (type.equals("window")){
dialog = new WindowDialog();
}else {
dialog = new HtmlDialog();
}
}
static void runBusinessLogic(){
dialog.renderWindow();
}
}