工厂解决的问题
- 客户端在调用是不想判断实例化哪一个类或者实例化的过程过于复杂。
- 在工厂模式中,具体的实现类创建过程对客户端是透明的,客户端不决定具体实例化哪一个类,而是交由“工厂”来实例化。
简单工厂模式
类图
简单工厂模式由三类角色组成:
- 抽象产品(Pizza)
- 具体产品(CheesePizza、VeggiePizza、ClamPizza)
- 工厂类(SimplePizzaFactory)
客户端代码(PizzaStore)
pulic class PizzaStore{
//添加工厂的引用
SimplePizzaFactory factory;
public PizzaStore(SimplePizzaFactory factory){
this.factory = factory;
}
//披萨来自于工厂
Pizza pizza = factory.createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}
简单工厂代码(SimplePizzaFactory)
public class SimplePizzaFactory(){
Pizza orderPizza(String type){
Pizza pizza;
if("cheese".equals(type)){
pizza = new CheesePizza();
}else if("greek".equals(type)){
pizza = new GreekPizza;
}
return pizza;
}
}
public class SimplePizzaFactory(){
//静态方法
static Pizza orderPizza(String type){
Pizza pizza;
if("cheese".equals(type)){
pizza = new CheesePizza();
}else if("greek".equals(type)){
pizza = new GreekPizza;
}
return pizza;
}
}
特点
- 简单工厂类是一个具体的类,非接口抽象类。
- 简单工厂类中具有一个重要的创建方法(orderPizza),利用if或者switch创建产品并返回。
- 创建方法也可以设置为静态方法,所以也可以称之为静态工厂方法。
缺点
- 扩展性差,不符合“开闭原则”,如果想要增加一种产品(比萨),需要修改工厂方法代码。
- 依赖参数(type)生产不同的产品。
工厂方法模式
定义
工厂方法模式:定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。
类图
创建者(工厂)
产品
工厂方法模式
工厂方法模式由四类角色组成:
- 抽象产品(Product)
- 具体产品(ConcreteCreator)
- 抽象工厂(Creator)
- 具体工厂(ConcreteCreator)
工厂模式代码实现
产品类
抽象产品类
public abstract class Pizza {
String name;
String dough;
String sauce;
ArrayList toppings = new ArrayList();
void prepare(){
System.out.println("Preparing "+name);
System.out.println("Tossing dough...");
System.out.println("Adding sauce...");
System.out.println("Adding toppings: ");
for(int i = 0;i<toppings.size();i++){
System.out.println(" "+toppings.get(i));
}
}
void bake(){
System.out.println("Bake for 25 minutes at 350");
}
void cut(){
System.out.println("Cutting the pizza into diagonal slices");
}
void box(){
System.out.println("Place pizza in official PizzaStore box");
}
public String getName(){
return name;
}
}
具体产品类(芝加哥风味)
public class ChicagoStyleCheesePizza extends Pizza {
public ChicagoStyleCheesePizza(){
name = "Chicago Style Deep Dish Cheese Pizza";
dough = "Extra Thick Crust Dough";
sauce = "Plum Tomato Sauce";
toppings.add("Shredded Mozzarella Cheese");
}
@Override
void cut(){
System.out.println("Cutting the pizza into square slices");
}
}
具体产品类(纽约风味)
public class NYStyleCheesePizza extends Pizza {
public NYStyleCheesePizza(){
name = "NY Style Sauce and Cheese Pizza";
dough = "Thin Crest Dough";
sauce = "Marinara Sauce";
toppings.add("Grated Reggiano Cheese");
}
}
工厂类
抽象工厂类
public abstract class PizzaStore{
public Pizza orderPizza(){
Pizza pizza;
pizza = createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
//现在把工厂对象移动到这个方法中
abstract Pizza createPizza();
}
具体工厂类(纽约披萨工厂)
public class NYStylePizzaStore extends PizzaStore{
@Override
Pizza createPizza(){
return new NYStyleCheesePizza();
}
}
具体工厂类(芝加哥披萨工厂)
public class ChicagoStyleCheeseStore extends PizzaStore{
@Override
Pizza createPizza(){
return new ChicagoStyleCheesePizza();
}
}
客户端代码
//纽约风味
NYPizzaFactory nyFactory = new NYPizzaFactory();
PizzaStore nyStore = new PizzaStore(nyFactory);
nyStore.orderPizza();
//芝加哥风味
ChicagoPizzaFactory chicagoFactory = new ChicagoPizzaFactory();
PizzaStore nyStore = new PizzaStore(chicagoFactory);
nyStore.orderPizza();
特点
- 解耦:创建者和产品实现类解耦,只依赖产品接口/抽象类(抽象产品),产品实现改动与创建者完全无关。
- 加入“开闭原则”(软件实体类、模块或者函数等等,应该可以扩展,但是不可以修改)。
- 将简单工厂的内部逻辑判断,移动到了客户端,在扩展新功能,简单工厂模式需要修改工厂类,工厂方法模式只需要修改客户端。
抽象工厂模式
定义
抽象工厂模式:提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。(可以理解为多个工厂方法的组合)
结构类图
简单工厂模式由四类角色组成:
- 抽象工厂(AbstractFactory):客户端直接引用,由未实现的工厂方法组成,子类必须实现其工厂方法创建产品家族。
- 具体工厂(ConcreteFactory):实现抽象工厂接口,负责实现工厂方法,一个具体工厂可以创建一组产品。
- 抽象产品(AbstractProduct):产品家族的父类,由此可以衍生很多子产品。
- 具体产品(Product):衍生自抽象产品,由工厂方法直接创建
抽象工厂模式代码实现
产品
抽象产品AbstractProductA和抽象产品AbstractProductB作为一个产品家族,每个具体工厂都能够生产一整组的产品
//抽象产品AbstractProductA
public interface AbstractProductA{
}
//具体产品ProductA1
public class ProductA1 implement AbstractProductA{
}
//具体产品ProductA2
public class ProductA2 implement AbstractProductA{
}
//抽象产品AbstractProductB
public interface AbstractProductB{
}
//具体产品ProductA1
public class ProductB1 implement AbstractProductB{
}
//具体产品ProductA2
public class ProductB2 implement AbstractProductB{
}
工厂
public interface AbstractFactory{
//定义两个工厂方法,两个工厂方法生产一整组产品
public void createProductA();
public void createProductB();
}
public class ConcreteFactory1{
@Override
public void createProductA(){
return new ProductA1();
}
@Override
public void createProductB(){
return new ProductB1();
}
}
public class ConcreteFactory2{
@Override
public void createProductA(){
return new ProductA2();
}
@Override
public void createProductB(){
return new ProductB2();
}
}
客户端
public class Client{
@Test
public void testAbatractFactory{
//客户的代码中只涉及抽象工厂,运行时将自动使用实际的工厂。
AbstractFactory factory1 = new ConcreteFactory1();
factory1.createProductA();
factory1.createProductB();
AbstractFactory factory2 = new ConcreteFactory2();
factory2.createProductA();
factory2.createProductB();
}
}
抽象工厂允许客户使用抽象的接口来创建一组相关的产品,而不需要知道(或关心)实际产出的具体产品是什么。这样一来,客户就从具体的产品中被解耦。
抽象工厂实战
类图
实现代码
产品家族
public interface Dough{
}
public class ThickCrustDough implements Dough{
}
public class ThinCrustDough implements Dough{
}
public interface Sauce{
}
public class PlumTomatoSauce implements Sauce{
}
public class MarinaraSauce implements Sauce{
}
public interface Cheese{
}
public class MozzarellaCheese implements Cheese{
}
public class ReggianoCheese implements Cheese{
}
抽象工厂
public interface PizzaIngredientFactory{
Dough createDough();
Sauce createSauce();
Cheese createCheese();
}
public class NYPizzaIngredientFactory implements PizzaIngredientFactory{
@Override
Dough createDough(){
return new ThinCrustDough();
}
@Override
Sauce createSauce(){
return new MarinaraSauce();
}
@Override
Cheese createCheese(){
return new ReggianoCheese();
}
}
public class ChicagoPizzaIngredientFactory implements PizzaIngredientFactory{
@Override
Dough createDough(){
return new ThickCrustDough();
}
@Override
Sauce createSauce(){
return new PlumTomatoSauce();
}
@Override
Cheese createCheese(){
return new MozzarellaCheese();
}
}
客户端(比萨店)
public class NYPizzaStore{
@Test
public Pizza createPizza(){
Pizza pizza = new Pizza();
//纽约工厂只生产纽约比萨的原料系列
PizzaIngredientFactory factory = new NYPizzaIngredientFactory();
pizza.setDough(factory.createDough);
pizza.setSauce(factory.crateSauce);
pizza.setCheese(factory.createCheese);
}
}
上述案例也可以类比成汽车生产工厂,两个比萨工厂类比为奔驰和宝马工厂,比萨原料类比成车型,比如轿车和SUV,奔驰工厂只生产奔驰的轿车和SUV,宝马工厂只生产宝马的轿车和SUV。
特点
优点
抽象工厂模式将具体产品的创建延迟到具体工厂的子类中,这样将对象的创建封装起来,可以减少客户端与具体产品类之间的依赖,从而使系统耦合度低,这样更有利于后期的维护和扩展。
缺点
抽象工厂模式很难支持新种类产品的变化。这是因为抽象工厂接口中已经确定了可以被创建的产品集合,如果需要添加新产品,此时就必须去修改抽象工厂的接口,这样就涉及到抽象工厂类的以及所有子类的改变,这就违背了"开闭原则"。