简单工厂类:处理创建对象(封装对象的创建)的类,通常声明为静态的。
简单工厂不能算是一个设计模式,比较像是一种编程习惯,用来封装对象的创建。使用静态方法好处是不需要使用创建对象的方法来实例化对象,缺点是不能通过继承来改变创建对象方法的行为。
简单工厂类图:
类图中,SimplePizzaFactory负责创建Pizza对象,PizzaStore是简单工厂类的客户,他们创建具体产品(CheesePizza, VegglePizza等)的行为都交给了简单工厂类来完成。
工厂方法:用来处理对象的创建,并将这样的行为封装到子类中。这样客户程序中关于超类的代码就喝子类对象创建代码解构了。
abstract Product factoryMethod(String type)
- 工厂方法是抽象abstract的,所以依赖子类来处理实际的对象创建。
- 工厂方法必须返回一个产品Product,超类中定义的方法通常使用到工厂方法的返回值。
- 工厂方法factoryMethod将客户(超类中的代码)和实际创建具体产品(具体对象)的代码分隔开来。
- 工厂方法可能需要参数(String type),也可能不需要参数,来指定所要的产品。
工厂方法模式:定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。
工厂方法模式类图:
工厂方法模式中,抽象的Creator提供了一个创建对象的方法的接口factoryMethod(),称为”工厂方法“。Creator的其他方法(如anOperation()方法)都可能用工厂方法返回的产品Product,但只有Creator的子类(ConcreteCreator等)真正实现了工厂方法并创建具体的产品(ConcreteProduct)。所有的产品必须实现Product接口,这样使用产品的类Creator就可以引用这个接口而不是具体的产品类。
注意:所谓”决定“,并不是指模式允许子类本身在运行时做决定,而是指在编写创建者类Creator的时候,不需要知道实际创建的产品是哪一个。选择了使用哪个子类(如ConcreteCreator)自然就决定了实际创建的产品(ConcreteProduct)是什么。
设计原则:要依赖抽象,不要依赖具体类。
不能让高层组件依赖低层组件,而且两者都应该依赖于抽象。该原则也成为依赖倒置原则。
高层组件是有其他低层组件定义其行为的类。当你实例化一个对象时,就是在依赖对象的具体类。例如下图中,PizzaStore就是一个高层组件,它的行为由NYCheesePizza等低层组件定义。
高层组件依赖低层组件例子:
如果低层组件NYCheesePizza的实现改变了,那么可能必须修改PizzaStore,因为PizzaStore依赖于NYChessePizza的实现。示例代码如下:
/**
*
* @author Yves
*/
public class PizzaStore {
Pizza pizza;
public Pizza orderPizza(String type){
pizza = new NYCheesePizza(); //PizzaStore依赖了NYCheesePizza类
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}
应用工厂方法后,实例化对象的代码就被封装起来了,使得高层组件PizzaStore不再依赖于低层组件,而依赖于Pizza这个抽象。见下图:
应用工厂方法后实现依赖倒置DI:
具体的类NYCheesePizza等依赖Pizza这个抽象,因为它们实现Pizza接口。现在依赖关系就从高层PizzaStore依赖于低层NYCheesePizza 倒置 为NYCheesePizza依赖于Pizza。
public abstract class PizzaStore {
Pizza pizza;
public Pizza orderPizza(String type){
pizza = this.createPizza(type); //创建对象的任务交给工厂方法
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
abstract Pizza createPizza(String type); //工厂方法
}
避免违反依赖倒置原则的方法:
- 变量不可以持有具体类的引用。(如果使用new就会持有具体类的引用,可以使用工厂方法来避免)
- 不要让类派生自具体类。(要派生自一个抽象:接口或抽象类)
- 不要覆盖积累中已经实现的方法。(基类中已经实现的方法应该由所有子类共享)
抽象工厂模式:提供一个接口,用于创建相关或依赖对象的家族,而不需要指定具体的类。
客户可以使用抽象的接口来创建一组相关的产品,而不需要知道实际产出的具体产品是什么。
抽象工厂通常用工厂方法来实现。抽象工厂提供的接口中,每个工厂方法负责创建一种具体产品,并且是利用实现抽象工厂的子类来提供具体的实现。
抽象工厂模式类图:
所有的具体工厂ConcreteFactory都必须实现抽象工厂定义的接口AbstractFactory,这个接口中的每个工厂方法,如CreateProductA,都负责创建一种具体的产品,如ProductA,具体创建的现实由具体工厂ConcreteFactory来提供。
/**
*
* @author Yves
*/
public interface AbstractFactory {
public AbstractProductA createProductA();
public AbstractProductB createProductB();
}
public class ConcreteFactory1 implements AbstractFactory{
private AbstractProductA productA;
private AbstractProductB productB;
@Override
public AbstractProductA createProductA() {
productA = new ProductA1();
return productA;
}
@Override
public AbstractProductB createProductB() {
productB = new ProductB1();
return productB;
}
}
public class ConcreteFactory2 implements AbstractFactory{
private AbstractProductA productA;
private AbstractProductB productB;
public ConcreteFactory2(){
}
@Override
public AbstractProductA createProductA() {
productA = new ProductA2();
return productA;
}
@Override
public AbstractProductB createProductB() {
productB = new ProductB2();
return productB;
}
}
public interface AbstractProductA {
}
public interface AbstractProductB {
}
public class ProductA1 implements AbstractProductA{
public ProductA1(){
System.out.println("Create a ProductA1");
}
}
public class ProductA2 implements AbstractProductA{
public ProductA2(){
System.out.println("Create a ProductA2");
}
}
public class ProductB1 implements AbstractProductB{
public ProductB1(){
System.out.println("Create a ProductB1");
}
}
public class ProductB2 implements AbstractProductB{
public ProductB2(){
System.out.println("Create a ProductB2");
}
}
public class Client {
private AbstractFactory factory;
private AbstractProductA productA;
private AbstractProductB productB;
public AbstractProductA createProductA(){
factory = new ConcreteFactory1(); //要创建一个产品,客户只需要使用其中一个具体工厂,而不需要实例化任何产品对象。
productA = factory.createProductA();
return productA;
}
public AbstractProductB createProductB(){
factory = new ConcreteFactory2(); //要创建一个产品,客户只需要使用其中一个具体工厂,而不需要实例化任何产品对象。
productB = factory.createProductB();
return productB;
}
}
public class FactoryTest {
public static void main(String[] args){
Client client = new Client();
client.createProductA();
client.createProductB();
}
}
run:
Create a ProductA1 //选择了ConcreteFactory1这个工厂,所以生产出ProductA1
Create a ProductB2 //选择了ConcreteFactory2这个工厂,所以生产出ProductB2
抽象工厂模式使用组合而不是继承(工厂方法模式使用继承把对象的创建委托给子类,子类实现工厂方法来创建对象),客户Client只跟接口AbstractProductA,AbstractProductB,和AbstratcFactory产生关系,在创建具体产品的时候,选择合适的具体工厂ConcreteFactory就可以生产出相应的产品,而不需要在客户Client里面实例化具体产品类,从而把Client与具体产品解耦。