工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
一、原始写法
在使用工厂模式之前,我们一般这样写
第一步、先创建一个超类
package lcl.mm.pattern.factory.simpledemo; import lombok.extern.slf4j.Slf4j; import java.util.ArrayList; @Slf4j public class Pizza { public String name; public String dough; public String sauce; public ArrayList topping = new ArrayList(); public void prepare(){ log.info("准备pizza"); log.info("揉面"); log.info("加酱"); log.info("添加调料"); } public void bake(){ log.info("烤pizza"); } public void cut(){ log.info("切pizza"); } public void box(){ log.info("打包pizza"); } }
第二步、该超类下可能存在多个子类
package lcl.mm.pattern.factory.simpledemo; public class BjPizza extends Pizza { public BjPizza(){ name = "北京风味的奶酪披萨"; dough = "北京面团"; sauce = "北京番茄酱"; topping.add("北京高级奶酪"); } }
package lcl.mm.pattern.factory.simpledemo; public class ShPizza extends Pizza { public ShPizza(){ name = "上海风味的奶酪披萨"; dough = "上海面团"; sauce = "上海番茄酱"; topping.add("上海高级奶酪"); } }
第三步,就是实际的创建对象和使用对象了
package lcl.mm.pattern.factory.simpledemo; import com.alibaba.fastjson.JSON; import lombok.extern.slf4j.Slf4j; @Slf4j public class PizzaStore { public Pizza orderPizz(String type){ Pizza pizza = null; if(type.equals("BJ")){ pizza = new BjPizza(); }else if(type.equals("SH")){ pizza = new ShPizza(); } pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); return pizza; } }
可以看到,直接在代码种new了对象,然后进行相关操作。那么这里就存在一个问题,就是每当我们新增一个新的对象时,都要新增 if 分支去创建新的对象,那么就不满足对 设计模式的 【开闭原则】,那么怎么处理呢?那么就可以使用简单设计模式。
二、简单工厂模式
简单设计模式就是把创建对象单独抽取成一个类,将类的创建与类的使用分离。
实际上简单工厂模式并不是一个设计模式,而更像一个编程习惯,但由于经常被使用,因此也经常被纳入设计模式里。
那么简单工厂模式第一步就是将创建类的代码单独抽取成一个类
package lcl.mm.pattern.factory.simpledemo; public class SimplePizzaFactory { public Pizza creatPizza(String type){ Pizza pizza = null; if(type.equals("BJ")){ pizza = new BjPizza(); }else if(type.equals("SH")){ pizza = new ShPizza(); } return pizza; } }
第二步便是先调用简单工厂类创建对象,然后在对对象进行操作。
package lcl.mm.pattern.factory.simpledemo; import com.alibaba.fastjson.JSON; import lombok.extern.slf4j.Slf4j; @Slf4j public class PizzaStore { private SimplePizzaFactory factory; public PizzaStore(SimplePizzaFactory factory){ this.factory = factory; } public Pizza orderPizza(String type){ Pizza pizza = factory.creatPizza("BJ"); pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); log.info("pizza return:【{}】", JSON.toJSONString(pizza)); return pizza; } }
但是上述还存在一个问题,就是对对象的使用被写死了,不能灵活调整,那么该如何处理呢?这里可以使用抽象工厂模式来处理
三、抽象工厂模式
第一步、先创建超类和对应子类
package lcl.mm.pattern.factory.demo; import lombok.extern.slf4j.Slf4j; import java.util.ArrayList; @Slf4j public abstract class Pizza { public String name; public String dough; public String sauce; public ArrayList topping = new ArrayList(); public void prepare(){ log.info("准备pizza"); log.info("揉面"); log.info("加酱"); log.info("添加调料"); } public void bake(){ log.info("烤pizza"); } public void cut(){ log.info("切pizza"); } public void box(){ log.info("打包pizza"); } public String getName(){ return name; } }
package lcl.mm.pattern.factory.demo; public class ShStyleCheesePizza extends Pizza { public ShStyleCheesePizza(){ name = "上海风味的奶酪披萨"; dough = "上海面团"; sauce = "上海番茄酱"; topping.add("上海高级奶酪"); } }
package lcl.mm.pattern.factory.demo; import lombok.extern.slf4j.Slf4j; @Slf4j public class BjStyleCheesePizza extends Pizza { public BjStyleCheesePizza(){ name = "北京风味的奶酪披萨"; dough = "北京面团"; sauce = "北京番茄酱"; topping.add("北京高级奶酪"); } public void cut(){ log.info("将pizza切成正方形"); } }
第二部、创建使用者
在这一步中,超类有一个抽象的创建对象方法,这样超类就不需要关心创建的具体是哪个对象
package lcl.mm.pattern.factory.demo; public abstract class PizzaStore { public Pizza orderPizza(String type){ Pizza pizza = creatPizza(type); pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); return pizza; } public abstract Pizza creatPizza(String type); }
package lcl.mm.pattern.factory.demo; public class ShPizzaStore extends PizzaStore { @Override public Pizza creatPizza(String type) { if(type.equals("cheese")){ return new ShStyleCheesePizza(); }else { return null; } } }
package lcl.mm.pattern.factory.demo; public class BjPizzaStore extends PizzaStore { @Override public Pizza creatPizza(String type) { if(type.equals("cheese")){ return new BjStyleCheesePizza(); }else { return null; } } }