工厂模式
我们先看一个具体需求
看一个披萨的项目:要便于披萨种类的扩展,要便于维护
1)披萨的种类很多(比如GreekPizz(希腊)、CheesePizz (奶酪)等)
2)披萨的制作有prepare(准备材料), bake(烘烤), cut(切割), box(打包)
3)完成披萨店订购功能。
传统方式怎么做?
代码
Pizza抽象类
/**
* @author 王庆华
* @version 1.0
* @date 2020/12/21 20:06
* @Description TODO
* @pojectname 披萨抽象类 设置为抽象类
*/
public abstract class Pizza {
//披萨名字
protected String name;
//抽象方法 准备原材料 不同的披萨,原材料是不同的
//因此做成抽象方法
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;
}
}
两种不同的Pizza种类
public class CheesePizza extends Pizza {
@Override
public void prepare() {
System.out.println("准备制作奶酪披萨的原材料");
}
}
public class GreekPizza extends Pizza {
@Override
public void prepare() {
System.out.println("给希腊披萨准备原材料");
}
}
订单发起类
/**
* @author 王庆华
* @version 1.0
* @date 2020/12/21 20:14
* @Description TODO
* @pojectname 订购披萨代码
*/
public class OrderPizza {
//构造器
public OrderPizza() {
Pizza pizza = null;
String orderType;//订购披萨类型是什么
do {
orderType = getType();
if (orderType.equals("greek")){
pizza = new GreekPizza();
pizza.setName("希腊披萨");
}else if (orderType.equals("cheese")){
pizza = new CheesePizza();
pizza.setName("奶酪披萨");
}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.println("input pizza 种类:");
String str = strin.readLine();
return str;
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
}
主类:披萨店
/**
* @author 王庆华
* @version 1.0
* @date 2020/12/21 20:22
* @Description TODO
* @pojectname 披萨店客户端,发起订购的类(主类)
*/
public class PizzaStore {
public static void main(String[] args) {
OrderPizza orderPizza = new OrderPizza();
}
}
优点和存在的问题
优点是比较好理解,简单易操作。
缺点是违反了设计模式的ocp原则,即对扩展开放,对修改关闭。即当我们给类增加新功能的时候,尽量不修改代码,或者尽可能少修改代码
比如我们这时要新增加一个Pizza的种类(Pepper披萨),我们需要做如下修改:
1.增加胡椒披萨,继承抽象披萨类
public class PepperPizza extends Pizza {
@Override
public void prepare() {
System.out.println("给胡椒披萨准备原材料");
}
}
2.我们就必须在OrderPizza中加入判断是不是胡椒披萨的逻辑
if (orderType.equals("greek")){
pizza = new GreekPizza();
pizza.setName("希腊披萨");
}else if (orderType.equals("cheese")){
pizza = new CheesePizza();
pizza.setName("奶酪披萨");
}else if (orderType.equals("pepper")){
pizza = new PepperPizza();
pizza.setName("胡椒披萨");
} else {
break;
}
加入我们分店多,OrderPizza有2,3,4,5,6……呢?岂不是每个都要改?
改进
分析:修改代码可以接受,但是如果我们在其它的地方也有创建Pizza的代码,就意味着,也需要修改,而创建Pizza的代码,往往有多处。
**思路:**把创建Pizza对象封装到-一个类中,这样我们有新的Pizza种类时,只需要修改该类就可,其它有创建到Pizza对象的代码就不需要修改了====>简单工厂模式
简单工厂模式
基本介绍
又称静态工厂模式
1)简单工厂模式是属于创建型模式,是工厂模式的一种。简单工厂模式是由一个工厂对象决定创建出哪一种产 品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式
2)简单工厂模式:定义了一个创建对象的类,由这个类来封装实例化对象的行为(代码)
3)在软件开发中,当我们会用到大量的创建某种、某类或者某批对象时,就会使用到工厂模式.
代码
/**
* @author 王庆华
* @version 1.0
* @date 2020/12/21 20:43
* @Description TODO
* @pojectname 简单工厂用来管理Pizza的生产
*/
public class SimpleFactory {
/**
* 根据我们的pizza类型,返回一个该类型的实例对象
* @param orderType pizza类型
* @return
*/
public Pizza createPizza(String orderType){
Pizza pizza = null;
System.out.println("使用简单工厂模式");
if (orderType.equals("greek")){
pizza = new GreekPizza();
pizza.setName("希腊披萨");
}else if (orderType.equals("cheese")){
pizza = new CheesePizza();
pizza.setName("奶酪披萨");
}else if (orderType.equals("pepper")){
pizza = new PepperPizza();
pizza.setName("胡椒披萨");
}
return pizza;
}
}
OrderPizza的变化
/**
* @author 王庆华
* @version 1.0
* @date 2020/12/21 20:14
* @Description TODO
* @pojectname 订购披萨代码
*/
public class OrderPizza {
//定义简单工厂对象
SimpleFactory simpleFactory;
Pizza pizza = null;
public void setSimpleFactory(SimpleFactory simpleFactory) {
String orderType = "";//orderType用户输入pizza类型
this.simpleFactory = simpleFactory;//设置一个简单工厂对象
do {
orderType = getType();//获取用户订购的pizza类型
pizza = this.simpleFactory.createPizza(orderType);
//输出制作pizza信息
if (pizza != null){
//订购成功
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}else {
System.out.println("预定失败,请检查是不是没有这个pizza类型");
break;
}
}while(true);
}
//构造器
public OrderPizza(SimpleFactory simpleFactory){
setSimpleFactory(simpleFactory);
}
//获取客户订购的披萨种类
private String getType(){
try {
BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
System.out.println("input pizza 种类:");
String str = strin.readLine();
return str;
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
}
客户端的变化
/**
* @author 王庆华
* @version 1.0
* @date 2020/12/21 20:22
* @Description TODO
* @pojectname 披萨店客户端,发起订购的类(主类)
*/
public class PizzaStore {
public static void main(String[] args) {
//使用简单工厂模式订购
new OrderPizza(new SimpleFactory());
System.out.println("退出程序");
}
}
我们来理解一下:首先我们new不同Pizza种类的代码,从OrderPizza中转移到了简单工厂模式,这样以后我们还要增加披萨种类的时候,就不用去管那么多的OrderPizza了,只需要在工厂模式中增加一个逻辑判断就行了,而且这个工厂是扩展方,符合了我们OOP的思想
在我们的OrderPizza中,引入了一个直接朋友简单工厂对象,由这个简单工厂对象给我们生产Pizza,我们的OrderPizza只需要拿到这个对象就行了,并不需要自己再去new了,符合修改关闭
更加方便的是,我们可以把简单工厂模式中的createPizza方法设置为静态方法,那我们的代码会变成什么呢?
简单工厂模式的变化只是把createPizza方法加static修饰
OrderPizza改变
package com.wang.factory.pizza.order;
import com.wang.factory.pizza.Pizza;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* @author 王庆华
* @version 1.0
* @date 2020/12/21 20:14
* @Description TODO
* @pojectname 订购披萨代码
*/
public class OrderPizza2 {
Pizza pizza = null;
String orderType = "";//orderType用户输入pizza类型
//构造器
public OrderPizza2(){
do {
orderType = getType();//获取用户订购的pizza类型
pizza = SimpleFactory.createPizza(orderType);
//输出制作pizza信息
if (pizza != null){
//订购成功
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}else {
System.out.println("预定失败,请检查是不是没有这个pizza类型");
break;
}
}while(true);
}
//获取客户订购的披萨种类
private String getType(){
try {
BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
System.out.println("input pizza 种类:");
String str = strin.readLine();
return str;
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
}
因为我们的createPizza变成静态模式了,我们就不需要在传递一个简单工厂对象了,可以直接通过类名调用,就不在需要set一个简单工厂对象了
两者差距不大,细节之处在于不是静态方法的时候,容易根据需求creat,效果相差不大,看业务需求