简单工厂模式虽然简单,但是存在一个问题。 因为简单工厂模式是调用工厂类中的工厂方法,然后传入不同的参数来创建不同的产品,当引入一个新产品时,就需要修改工厂类,不符合“开闭原则”。 工厂模式不再提供一个工厂类来创建所有的产品对象,而是根据不同的产品来提供不同的工厂类。
定义 :定义一个用于创建对象的接口,让子类决定哪一个类实例化,创建具体的产品对象。工厂方法模式让一个类的实例化延迟到其子类。工厂方法模式又简称为工厂模式,又可称作虚拟构造器模式或多态工厂模式。工厂模式是一种类创建型模式
在工厂模式结构图有如下几个角色:
与简单工厂模式相比,我们可以看到工厂模式多了一个抽象工厂角色。 抽象工厂可以是接口,也可以是抽象类或是类。
代码实现:
Product (抽象产品)
/**
* @program
* @Desc 抽象产品
* @Author 游戏人日常
* @CreateTime 2019/07/14--13:38
*/
public interface Product {
}
ConcreteProduct(具体产品)
/**
* @program
* @Desc 具体产品A
* @Author 游戏人日常
* @CreateTime 2019/07/14--13:39
*/
public class ConcreteProductA implements Product{
}
/**
* @program
* @Desc 具体产品B
* @Author 游戏人日常
* @CreateTime 2019/07/14--13:40
*/
public class ConcreteProductB implements Product {
}
Factory(抽象工厂)
/**
* @program
* @Desc 抽象工厂
* @Author 游戏人日常
* @CreateTime 2019/07/14--13:42
*/
public interface Factory {
public Product factoryMrthod();
}
ConcreteFactory(具体工厂)
/**
* @program
* @Desc 具体工厂 A
* @Author 游戏人日常
* @CreateTime 2019/07/14--13:46
*/
public class ConcreteFactoryA implements Factory {
@Override
public Product factoryMrthod() {
return new ConcreteProductA();
}
}
/**
* @program
* @Desc 具体工厂 B
* @Author 游戏人日常
* @CreateTime 2019/07/14--13:48
*/
public class ConcreteFactoryB implements Factory {
@Override
public Product factoryMrthod() {
return new ConcreteProductB();
}
}
客户端测试
/**
* @program
* @Desc 客户端测试
* @Author 游戏人日常
* @CreateTime 2019/07/14--13:51
*/
public class Test {
public static void main(String [] args){
//获取产品 A 只需获取 工厂 A
Factory concreteFactoryA=new ConcreteFactoryA();
Product productA= concreteFactoryA.factoryMrthod();
//获取产品 B 只需获取 工厂 B
Factory concreteFactoryB=new ConcreteFactoryB();
Product productB= concreteFactoryB.factoryMrthod();
}
}
我们可以看到客户端想要获取哪个具体厂品时,只需要跟据不同工厂来获取。 不像简单工厂模式中的一样,通过参数不同来获取。
在UML类图可以看到,在工厂类中重载了工厂方法, 以不同的方法来创建。
代码实现:
Factory(抽象工厂)
/**
* @program
* @Desc 抽象工厂
* @Author 游戏人日常
* @CreateTime 2019/07/14--13:42
*/
public interface Factory {
public Product factoryMrthod();
public Product factoryMrthod(String args);
public Product factoryMrthod(int args);
}
ConcreteFactory (具体的工厂)
/**
* @program
* @Desc 具体工厂 A
* @Author 游戏人日常
* @CreateTime 2019/07/14--13:46
*/
public class ConcreteFactoryA implements Factory {
@Override
public Product factoryMrthod() {
Product productA = new ConcreteProductA();
//一般为默认方式创建产品
return productA;
}
@Override
public Product factoryMrthod(String args) {
Product productA = new ConcreteProductA();
// 有时创建产品时 产品对象需要String 型参数
return productA;
}
@Override
public Product factoryMrthod(int args) {
Product productA = new ConcreteProductA();
// 有时创建产品时 产品对象需要int 型参数
return productA;
}
}
//具体工厂 B ,也是如此 代码就不写了。
客户端测试:
/**
* @program
* @Desc 客户端测试
* @Author 游戏人日常
* @CreateTime 2019/07/14--13:51
*/
public class Test {
public static void main(String [] args){
//获取产品 A 只需获取 工厂 A
Factory concreteFactoryA=new ConcreteFactoryA();
Product productA1= concreteFactoryA.factoryMrthod("A");
Product productA2= concreteFactoryA.factoryMrthod(0);
Product productA3= concreteFactoryA.factoryMrthod();
}
}
在抽象工厂方法中定义了几个重载的方法,在具体的工厂类中实现了这些工厂方法,这些方法可以包含不同的业务来满足不同产品对象的需求。
有时候为了简化客户端的使用,我们可以隐藏工厂方法,直接在工厂类中调用产品类中的业务方法。客户端无需调用工厂方法来创建产品,然后调用产品业务方法。
代码如下:
Product(抽象产品)
/**
* @program
* @Desc 抽象产品
* @Author 游戏人日常
* @CreateTime 2019/07/14--13:38
*/
public interface Product {
public void productMethod();
}
ConcreteProduct (具体产品)
/**
* @program
* @Desc
* @Author 游戏人日常
* @CreateTime 2019/07/14--13:39
*/
public class ConcreteProductA implements Product{
@Override
public void productMethod() {
System.out.println("A 产品业务方法!!!");
}
}
Factory(抽象工厂)
/**
* @program
* @Desc 抽象工厂 改为抽象类
* @Author 游戏人日常
* @CreateTime 2019/07/14--13:42
*/
public abstract class Factory {
public abstract Product factoryMrthod();
//产品业务方法
public void productMethod(){
Product product=this.factoryMrthod();
product.productMethod();
}
}
ConcreteFactory (具体工厂)
/**
* @program
* @Desc 具体工厂 A
* @Author 游戏人日常
* @CreateTime 2019/07/14--13:46
*/
public class ConcreteFactoryA extends Factory {
Product productA;
@Override
public Product factoryMrthod() {
return new ConcreteProductA();;
}
}
客户端测试:
**
* @program
* @Desc 客户端测试
* @Author 游戏人日常
* @CreateTime 2019/07/14--13:51
*/
public class Test {
public static void main(String [] args){
ConcreteFactoryA factoryA= new ConcreteFactoryA();
factoryA.productMethod(); //输出结果 : A 产品业务方法!!!
}
}
把产品的业务方法移到工厂类中,可以直接使用工厂对象来调用产品的业务方法。无需使用工厂方法来获取产品,然后调用业务方法。
工厂模式是简单工厂模式的延伸,它继承了简单工厂模式的优点,同时还解决了简单工厂模式中的一些不足。
上面出现两种工厂模式的变形: 1 : 重载工厂方法 2: 隐藏工厂方法
工厂模式优缺点: