需求
通过一个具体案例来分析工厂模式:一个披萨订购项目,要便于披萨种类的扩展,要便于维护。
- 披萨的种类很多(比如GeekPizz、CheesePizza等)
- 披萨的制作有prepare,bake,cut,box
- 完成披萨订购功能
传统方式实现
代码实现:
/*将pizza类设计为抽象类*/
public abstract class Pizza {
protected String name; //名字
//准备原材料,不同的pizza不一样,我们设计为抽象方法
public abstract void prepare();
public void bake() {
System.out.println(name + " baking;");
}
public void cut() {
System.out.println(name + " cutting;");
}
//打包
public void box() {
System.out.println(name + " boxing;");
}
public void setName(String name) {
this.name = name;
}
}
GreekPizza
public class GreekPizza extends Pizza {
@Override
public void prepare() {
System.out.println("给希腊披萨准备原材料");
}
}
CheesePizza
public class CheesePizza extends Pizza {
@Override
public void prepare() {
System.out.println("制作奶酪披萨提供原材料");
}
}
然后我们创建一个工厂类
public class OrderPizza {
//构造器
public OrderPizza(){
Pizza pizza= null;
String orderType;//订购披萨的类型
do {
orderType = gettype();
if (orderType.equals("greek")){
pizza = new GreekPizza();
pizza.setName(orderType);
}else if (orderType.equals("cheese")){
pizza = new CheesePizza();
pizza.setName(orderType);
}else {
break;
}
//输出Pizza的制作过程
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}while (true);
}
//写一个方法,可以获取客户希望订购的披萨种类
private String gettype(){
try {
BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
System.out.print("input pizza type:");
String str = strin.readLine();
return str;
}catch (IOException e){
e.printStackTrace();
return "";
}
}
}
客户端测试代码:
public class PizzaStore {
public static void main(String[] args) {
new OrderPizza();
}
}
在创建对象的时候,会执行构造器中方法,在构造器方法中有一个String gettype()
方法用来给用户提供输入想要的披萨种类。
传统方式的优缺点
- 比较好理解
- 缺点是违反了是设计模式中的OCP原则(即开闭原则),对扩展开放,对修改关闭。当我们增加新的种类的时候,尽量不该变原有的代码。
- 比如我们这要新增一个Pizza种类,我们需要都OrderPizza类中的代码进行修改。
改进思路:
分析:修改的代码可以接受,但是如果我们在其他地方也有创建Pizza的代码,就意味着,也需要进行修改,而创建Pizza代码,往往有许多处。
思路:把创建Pizza对象封装到一个类中,这样我们有心的Pizza种类时,只需要修改类即可,其他有创建到Pizza对象的代码就不需要修改代码了->简单工厂模式。
简单工厂模式实现
代码示例:
/**
* 简单工厂类
* @Author Zhao
* @Date 2021-06-24 下午 5:05
* @Version 1.0
*/
public class SimpleFactory {
public Pizza pizza =null;
//根据OrderType返回对应的Pizza对象
public Pizza creatPizza(String type){
System.out.println("使用简单工厂模式");
if (type.equals("greek")){
pizza = new GreekPizza();
pizza.setName(type);
}else if (type.equals("cheese")){
pizza = new CheesePizza();
pizza.setName(type);
}
return pizza;
}
}
/**
* @Author Zhao
* @Date 2021-06-24 下午 4:26
* @Version 1.0
*/
public class OrderPizza {
//构造器
public OrderPizza(SimpleFactory simpleFactory){
setFactory(simpleFactory);
}
//定义一个简单工厂对象
SimpleFactory simpleFactory;
private void setFactory(SimpleFactory simpleFactory){
String orderType = "";//用户输入
this.simpleFactory = simpleFactory;//设置简单工厂对象
do {
orderType = gettype();
Pizza pizza = this.simpleFactory.creatPizza(orderType);
if (pizza==null){
break;
}
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}while (true);
}
//写一个方法,可以获取客户希望订购的披萨种类
private String gettype(){
try {
BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
System.out.print("input pizza type:");
String str = strin.readLine();
return str;
}catch (IOException e){
e.printStackTrace();
return "";
}
}
}
简单工厂模式也叫静态工厂模式,一般工厂模式中方法未Static方法。
//简单工厂模式 也叫静态工厂模式
public static Pizza creatPizza2(String type) {
System.out.println("使用简单工厂模式2");
if (type.equals("greek")) {
pizza = new GreekPizza();
pizza.setName(type);
} else if (type.equals("cheese")) {
pizza = new CheesePizza();
pizza.setName(type);
}
return pizza;
}
工厂方法模式
我们改变一下需求:
披萨项目的新需求:客户在点披萨时,可以点不同口味的披萨,比如北京的奶酪Pizza、或者是伦敦的Pizza、伦敦的胡椒Pizza。
分析:
使用简单工厂模式,创建不同的简单工厂类,比如BJPizzaSimpleFactory、LDPizzaDimpleFactory等等。从当前这个案例来说,也是可以的,但是考虑到项目的规模,以及软件的可维护性、可扩展性并不是特别好
那么我们就可以使用工厂方法模式
工厂方法模式介绍
工厂方法模式设计方案:将披萨项目的实例化功能抽象成抽象方法,在不同的口味点餐类中具体实现。
工厂方法模式:定义一个创建对象的抽象方法,由子类决定要实例化的类。工厂方法模式将对象的实例化推迟到子类。
public abstract class OrderPizza {
Pizza pizza = null;
String orderType = "";
//定义一个抽象方法,createPizza,让各个工厂的子类自己去实现
abstract Pizza creatFactory(String orderType);
public OrderPizza() {
do {
orderType = gettype();
//抽象方法,由子类去实现,执行时动态绑定到子类的实现
Pizza pizza = creatFactory(orderType);
if (pizza == null)
break;
pizza.prepare();
pizza.bake();
} while (true);
System.out.println("退出制作");
}
//写一个方法,可以获取客户希望订购的披萨种类
private String gettype() {
try {
BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
System.out.print("input pizza type:");
String str = strin.readLine();
return str;
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
}
public class BJOrderPizza extends OrderPizza {
Pizza pizza = null;
@Override
Pizza creatFactory(String orderType) {
if (orderType.equals("cheese")){
pizza = new BJCheesePizza();
}else if (orderType.equals("greek")){
pizza = new BJGreekPizza();
}
return pizza;
}
}
执行流程:
Orderpizza orderPizza = new BJOrderPizza()
//会去执行父类构造器中的方法
/*
进入循环-》执行gettype()让用户输入对应的披萨种类
然后执行abstract Pizza creatFactory(String orderType);抽象方法
因为为抽象方法,所以会去找对应的子类的实现。
*/
执行结果
input pizza type:cheese
制作奶酪披萨提供原材料
null baking;
input pizza type:
这里抽象方法在执行的时候,回去找实现类中的实现方法去执行。
抽象工厂模式
基本介绍
- 抽象工厂模式:定义一个interface用于创建相关或者有依赖关系的对象簇,无需知名具体的类。
- 抽象工厂模式可以将简单工厂模式和工厂方法模式进行整合。
- 从设计层面来看,抽象工厂模式就是对简单工厂模式的改进(或者称为进一步的抽象)
- 将工厂抽象分为两层,AbsFactory(抽象工厂)和具体实现的工厂子类。程序员可以根据创建对象类型使用对应的工厂子类。这样将简单工厂变成了工厂簇。更利于代码的维护和扩展。
OrderPizza中聚合了抽象接口
具体的BJ\LD工厂实现接口,
OrderPizaa接受具体的实现工厂,调用对应的工厂的createPizza方法,从而实现生产对应的Pizza
接口代码:
/**一个抽象工厂模式的抽象层()接口
* @Author Zhao
* @Date 2021-06-24 下午 8:27
* @Version 1.0
*/
public interface AbsFactory {
//让下面的工厂子类来具体实现
Pizza createPizza(String orderType);
}
北京工厂:
/**BJ工厂子类
* @Author Zhao
* @Date 2021-06-24 下午 8:29
* @Version 1.0
*/
public class BJFactory implements AbsFactory {
@Override
public Pizza createPizza(String orderType) {
Pizza pizza = null;
if (orderType.equals("cheese")){
pizza = new BJCheesePizza();
}else if (orderType.equals("greek")){
pizza = new BJGreekPizza();
}
return pizza;
}
}
伦敦工厂
/**LD工厂子类
* @Author Zhao
* @Date 2021-06-24 下午 8:29
* @Version 1.0
*/
public class LDFactory implements AbsFactory {
@Override
public Pizza createPizza(String orderType) {
Pizza pizza = null;
if (orderType.equals("cheese")){
pizza = new LDCheesePizza();
}else if ("greek".equals(orderType)){
pizza = new LDGreekPizza();
}
return pizza;
}
}
OrderPizza
public class OrderPizza {
AbsFactory absFactory;
public void setAbsFactory(AbsFactory absFactory) {
this.absFactory = absFactory;
Pizza pizza = null;
String orderType = "";
do {
orderType = gettype();
pizza = absFactory.createPizza(orderType);
if (pizza == null)
break;
pizza.prepare();
pizza.bake();
}while (true);
}
//写一个方法,可以获取客户希望订购的披萨种类
private String gettype() {
try {
BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
System.out.print("input pizza type:");
String str = strin.readLine();
return str;
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
}
工厂模式小节
- 工厂模式的意义。将实例化对象的代码提取出来,放到一个类中统一管理和维护,达到和主项目的依赖关系的解耦,从而提高项目的扩展性和可维护性。
- 三种工厂模式
设计模式的依赖抽象原则
- 创建对象实例时,不要直接new类,而是把这个new类的动作放在一个工厂的方法中,并返回。有的书上说,变量不要直接持有具体类的引用。
- 不要让类继承具体类,而是继承抽象类或是实现接口interface
- 不要覆盖基类中已经实现的方法。