上文我们提到了简单工厂模式,但是简单工厂也会存在一些问题,具体出现哪些问题可以看这里,所以我们这里就用工厂方法模式来从新修改下代码
抽象工厂模式介绍
抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。
还是先提一个需求
披萨需求 :订阅披萨套餐(披萨加雪碧)
1.奶酪披萨和雪碧
2.希腊披萨和可口可乐
我们先按照工厂方法模式写
抽象产品和具体产品类
披萨
package com.zjh.designmodel.factory.methodfactory.entiy;
import org.springframework.util.StringUtils;
/**
* @Author: zjh
* @Description: 披萨需求 增加套餐
* CheesePizza+可口可乐
* GreekPizza+雪碧
* @Date: Created in 2020/4/28 14:14
* Modified by:
*/
public abstract class PizzaAbstract {
protected String name;
public void setName(String name) {
this.name = name;
}
public abstract void prepare();
public void bake() {
System.out.println(name+"披萨已经烘焙好了");
}
public void cut() {
System.out.println(name+"披萨已经切割完成");
}
public void box() {
System.out.println(name+"披萨已经装盒了");
}
}
package com.zjh.designmodel.factory.methodfactory.entiy;
/**
* @Author: zjh
* @Description:
* @Date: Created in 2020/5/6 19:24
* Modified by:
*/
public class CheesePizza extends PizzaAbstract {
@Override
public void prepare() {
System.out.println("CheesePizz披萨原材料准备好了");
this.name="CheesePizz";
}
}
package com.zjh.designmodel.factory.methodfactory.entiy;
/**
* @Author: zjh
* @Description:
* @Date: Created in 2020/5/6 19:22
* Modified by:
*/
public class GreekPizza extends PizzaAbstract {
@Override
public void prepare() {
System.out.println("GreekPizz披萨原材料准备好了");
this.name="GreekPizz";
}
}
饮料
package com.zjh.designmodel.factory.methodfactory.entiy;
/**
* @Author: zjh
* @Description: 饮料抽象类
* @Date: Created in 2020/5/12 18:09
* Modified by:
*/
public abstract class DrinkAbstract {
public String name;
public void setName(String name) {
this.name = name;
}
//准备原材料
public abstract void paper();
public void box(){
System.out.println(name+"饮料装盒");
}
}
package com.zjh.designmodel.factory.methodfactory.entiy;
/**
* @Author: zjh
* @Description:
* @Date: Created in 2020/5/12 18:13
* Modified by:
*/
public class SpriteDrink extends DrinkAbstract {
@Override
public void paper() {
System.out.println("雪碧原材料准备好了");
this.name="雪碧";
}
}
package com.zjh.designmodel.factory.methodfactory.entiy;
/**
* @Author: zjh
* @Description:
* @Date: Created in 2020/5/12 18:12
* Modified by:
*/
public class CokeDrink extends DrinkAbstract {
@Override
public void paper() {
System.out.println("可口可乐原材料准备好了");
this.name="可口可乐";
}
}
工厂类和他的子类
披萨工厂
package com.zjh.designmodel.factory.methodfactory;
import com.zjh.designmodel.factory.methodfactory.entiy.PizzaAbstract;
/**
* @Author: zjh
* @Description:
* @Date: Created in 2020/5/11 20:09
* Modified by:
*/
public interface PizzaFactoryService {
PizzaAbstract createPizza();
}
package com.zjh.designmodel.factory.methodfactory;
import com.zjh.designmodel.factory.methodfactory.entiy.CheesePizza;
import com.zjh.designmodel.factory.methodfactory.entiy.PizzaAbstract;
/**
* @Author: zjh
* @Description:
* @Date: Created in 2020/5/11 20:12
* Modified by:
*/
public class CheesePizzaFactory implements PizzaFactoryService {
@Override
public PizzaAbstract createPizza() {
return new CheesePizza();
}
}
package com.zjh.designmodel.factory.methodfactory;
import com.zjh.designmodel.factory.methodfactory.entiy.GreekPizza;
import com.zjh.designmodel.factory.methodfactory.entiy.PizzaAbstract;
/**
* @Author: zjh
* @Description:
* @Date: Created in 2020/5/11 20:13
* Modified by:
*/
public class GreekPizzaFactory implements PizzaFactoryService {
@Override
public PizzaAbstract createPizza() {
return new GreekPizza();
}
}
饮料工厂和其子类
package com.zjh.designmodel.factory.methodfactory;
import com.zjh.designmodel.factory.methodfactory.entiy.DrinkAbstract;
/**
* @Author: zjh
* @Description:
* @Date: Created in 2020/5/13 18:31
* Modified by:
*/
public interface DrinkFactoryService {
DrinkAbstract creatDrink();
}
package com.zjh.designmodel.factory.methodfactory;
import com.zjh.designmodel.factory.methodfactory.entiy.CokeDrink;
import com.zjh.designmodel.factory.methodfactory.entiy.DrinkAbstract;
/**
* @Author: zjh
* @Description:
* @Date: Created in 2020/5/12 18:14
* Modified by:
*/
public class CokeDrinkFactory implements DrinkFactoryService {
@Override
public DrinkAbstract creatDrink() {
return new CokeDrink();
}
}
package com.zjh.designmodel.factory.methodfactory;
import com.zjh.designmodel.factory.methodfactory.entiy.DrinkAbstract;
import com.zjh.designmodel.factory.methodfactory.entiy.SpriteDrink;
/**
* @Author: zjh
* @Description:
* @Date: Created in 2020/5/12 18:15
* Modified by:
*/
public class SpriteDrinkFactory implements DrinkFactoryService {
@Override
public DrinkAbstract creatDrink() {
return new SpriteDrink();
}
}
订单类
package com.zjh.designmodel.factory.methodfactory.entiy;
import com.zjh.designmodel.factory.methodfactory.DrinkFactoryService;
import com.zjh.designmodel.factory.methodfactory.PizzaFactoryService;
/**
* @Author: zjh
* @Description: 订购Pizz
* @Date: Created in 2020/5/6 19:33
* Modified by:
*/
public class OrderPizza {
public PizzaFactoryService pizzaFactoryService;
public DrinkFactoryService drinkFactoryService;
public PizzaFactoryService getPizzaFactoryService() {
return pizzaFactoryService;
}
public DrinkFactoryService getDrinkFactoryService() {
return drinkFactoryService;
}
public OrderPizza(PizzaFactoryService pizzaFactoryService,DrinkFactoryService drinkFactoryService){
this.pizzaFactoryService=pizzaFactoryService;
this.drinkFactoryService=drinkFactoryService;
}
}
测试
工厂方法模式总结:
当我们增加一个产品工厂的时候(饮料工厂)我们会发现我们不仅新增了工厂还去修改了订单类,这样不就违反了opc原则么,所以工厂方法模式在解决增加共一个工厂产品是可以的,增加工厂就不行了,下面我们用抽象工厂模式来修改代码。
抽象工厂模式的思路:
我理解的抽象工厂模式其实就相当于在工厂方法模式的基础上又增加了简单工厂模式,比如我们可以吧所有工厂聚合到一个抽象工厂类里面(类似于前面简单工厂模式吧所有逻辑放在一个类里面),这样当我们增加工厂的时候我们只需要在抽象工厂类加一个相对于的工厂就行了,不需要去修改订单类。这样不就遵守了opc原则么
抽象工厂的类图(类图的介绍和软件安装看这里)
修改后的代码(其他都不需要修改,我们只需要创建一个抽象工厂类和修改下订单类就行了)
抽象工厂类
package com.zjh.designmodel.factory.abstractFactory;
import com.zjh.designmodel.factory.abstractFactory.entiy.DrinkAbstract;
import com.zjh.designmodel.factory.abstractFactory.entiy.PizzaAbstract;
/**
* @Author: zjh
* @Description:
* @Date: Created in 2020/5/12 18:05
* Modified by:
*/
public class GoodsFactory {
private PizzaAbstract pizza;
private DrinkAbstract drink;
public GoodsFactory(){
}
public GoodsFactory(PizzaFactory pizzaFactory,DrinkFactory drinkFactory){
this.pizza = pizzaFactory.createPizza();
this.drink = drinkFactory.creatDrink();
}
public PizzaAbstract getPizza() {
return pizza;
}
public DrinkAbstract getDrink() {
return drink;
}
}
订单类
package com.zjh.designmodel.factory.abstractFactory.entiy;
import com.zjh.designmodel.factory.abstractFactory.GoodsFactory;
/**
* @Author: zjh
* @Description: 订购Pizzt套餐
* 1.奶酪披萨加雪碧
* 2.希腊披萨加可乐
* @Date: Created in 2020/5/6 19:33
* Modified by:
*/
public class OrderGoods {
private GoodsFactory goodsFactory;
public GoodsFactory getGoodsFactory() {
return goodsFactory;
}
public OrderGoods(GoodsFactory goodsFactory){
this.goodsFactory=goodsFactory;
}
}
测试
抽象工厂模式总结:
我们用抽象工厂模式吧代码改了以后会发现当我们想在增加一个工厂(比如套餐里面又要加汉堡),这时候我们只需要在抽象工厂类(GoodsFactory)加一个汉堡工厂的属性以及构造方法就可以了,不在需要去修改订单类
JDK源码(Collection看成我们OrderGoods抽象类,List和Set等这些可以看成我们的披萨工厂和饮料工厂,Arraylist这些我们可以看成是我们具体奶酪披萨或者可口可乐)
工厂模式总结(简单工厂、工厂方法、抽象工厂)
- 简单工厂适用于产品不多并且你后续不会增加产品的场景(因为你这个如果也用工厂方法或者抽象工厂模式来写的话会造成代码冗余,因为后者每次增加一个产品会增加一个具体的产品类以及工厂类)
- 工厂方法模式适用于增加同一个工厂的产品,对于增加工厂无能为力(比如披萨需求:增加一个胡椒披萨是ok的,但是当我们想增加饮料的时候发现还是需要修改订单类)
- 抽象工厂模式即可以满足增加同一产品也可以满足增加工厂
以上是自己的个人见解,有错的地方欢迎各位大佬指出。