工厂模式
将创建对象new的动作,进行工厂模式的封装调用,达到项目层次依赖关系的解耦,也就是“变量不要直接持有具体类的引用”。
对象各种需求过多时可用到工厂模式,达到依赖的解耦
1、披萨订购系统,披萨种类包含:伦敦胡椒披萨、伦敦奶酪披萨、北京胡椒披萨、北京奶酪披萨(四种披萨类型,以后还将扩展)
2、您需要一辆汽车,可以直接从工厂里面提货,而不用去管这辆汽车是怎么做出来的,以及这个汽车里面的具体实现
以下均用 披萨订购系统 举例说明:
1、简单工厂
步骤如下:
1) Pizza抽象类,包括披萨名称制作流程,让其子类实现
2) 写一个简单工厂,维护不同的披萨类型
3) 订购披萨,套用简单工厂的动态下订单
4) 代码实现
Pizza类
/**
* @author 漆剑
* @date 2021-03-27
* @description
*/
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;
}
}
CheesePizza实现类(其他实现大同小异)
/**
* @author 漆剑
* @date 2021-03-27
* @description
*/
public class CheesePizza extends Pizza {
@Override
public void prepare() {
// TODO Auto-generated method stub
System.out.println(" 给制作奶酪披萨 准备原材料 ");
}
}
SimpleFactory类(工厂,重点代码)
/**
* @author 漆剑
* @date 2021-03-27
* @description
*/
//简单工厂类
public class SimpleFactory {
//更加orderType 返回对应的Pizza 对象
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 漆剑
* @date 2021-03-27
* @description
*/
public class OrderPizza {
//定义一个简单工厂对象
SimpleFactory simpleFactory;
Pizza pizza = null;
//构造器
public OrderPizza(SimpleFactory simpleFactory) {
setFactory(simpleFactory);
}
public void setFactory(SimpleFactory simpleFactory) {
String orderType = ""; //用户输入的
this.simpleFactory = simpleFactory; //设置简单工厂对象
do {
orderType = getType();
pizza = this.simpleFactory.createPizza(orderType);
//输出pizza
if(pizza != null) { //订购成功
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
} else {
System.out.println(" 订购披萨失败 ");
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 "";
}
}
}
客户端调用
/**
* @author 漆剑
* @date 2021-03-27
* @description
*/
public class PizzaStore {
public static void main(String[] args) {
// TODO Auto-generated method stub
//使用简单工厂模式
new OrderPizza(new SimpleFactory());
System.out.println("~~退出程序~~");
}
}
优缺点说明:
在单维度(胡椒披萨、奶酪披萨...)加工使用时可以使用简单工厂模式,但是在多维度(北京胡椒披萨、南京奶酪
披萨...)使用时,则不适用简单工厂。
2、工厂方法
披萨项目新的需求:客户在点披萨时,可以点不同口味的披萨,比如 北京的奶酪 pizza、北京的胡椒 pizza 或者是伦敦的奶酪 pizza、伦敦的胡椒 pizza
步骤如下:
1) Pizza抽象类,包括披萨名称制作流程,让其子类实现(新增地域维度,如北京xx披萨...)
2) 写一个或多个工厂方法,继承父类,根据地域来维护披萨类型
3) 订购披萨,让工厂方法去继承订购
4) 代码实现
Pizza类
/**
* @author 漆剑
* @date 2021-03-27
* @description
*/
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;
}
}
BJCheesePizza实现类(其他实现大同小异)
/**
* @author 漆剑
* @date 2021-03-27
* @description
*/
public class BJCheesePizza extends Pizza {
@Override
public void prepare() {
// TODO Auto-generated method stub
setName("北京的奶酪pizza");
System.out.println(" 北京的奶酪pizza 准备原材料");
}
}
BJOrderPizza类(工厂方法,继承OrderPizza,重点代码)
/**
* @author 漆剑
* @date 2021-03-27
* @description
*/
public class BJOrderPizza extends OrderPizza {
@Override
Pizza createPizza(String orderType) {
Pizza pizza = null;
if(orderType.equals("cheese")) {
pizza = new BJCheesePizza();
} else if (orderType.equals("pepper")) {
pizza = new BJPepperPizza();
}
// TODO Auto-generated method stub
return pizza;
}
}
OrderPizza类(披萨订单)
/**
* @author 漆剑
* @date 2021-03-27
* @description
*/
public abstract class OrderPizza {
//定义一个抽象方法,createPizza , 让各个工厂子类自己实现
abstract Pizza createPizza(String orderType);
// 构造器
public OrderPizza() {
Pizza pizza = null;
String orderType; // 订购披萨的类型
do {
orderType = getType();
pizza = createPizza(orderType); //抽象方法,由工厂子类完成
//输出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 漆剑
* @date 2021-03-27
* @description
*/
public class PizzaStore {
public static void main(String[] args) {
String loc = "bj";
if (loc.equals("bj")) {
//创建北京口味的各种Pizza
new BJOrderPizza();
} else {
//创建伦敦口味的各种Pizza
new LDOrderPizza();
}
}
}
优缺点说明:
工厂方法采用继承,能够提供一种框架,约束子类。但是容易产生类爆炸问题。
3、抽象工厂
需求还是和工厂方法一样,只是代码写法改变
步骤如下:
1) Pizza抽象类,包括披萨名称制作流程,让其子类实现(新增地域维度,如北京xx披萨...)
2) 写一个抽象工厂,让一个或多个子类实现工厂
3) 订购披萨,引入抽象工厂
4) 代码实现
Pizza类
/**
* @author 漆剑
* @date 2021-03-27
* @description
*/
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;
}
}
BJCheesePizza实现类(其他实现大同小异)
/**
* @author 漆剑
* @date 2021-03-27
* @description
*/
public class BJCheesePizza extends Pizza {
@Override
public void prepare() {
// TODO Auto-generated method stub
setName("北京的奶酪pizza");
System.out.println(" 北京的奶酪pizza 准备原材料");
}
}
AbsFactory类(抽象工厂模式的抽象层)
/**
* @author 漆剑
* @date 2021-03-27
* @description
*/
public interface AbsFactory {
//让下面的工厂子类来 具体实现
public Pizza createPizza(String orderType);
}
BJFactory类(工厂子类,实现抽象工厂)
/**
* @author 漆剑
* @date 2021-03-27
* @description
*/
public class BJFactory implements AbsFactory {
@Override
public Pizza createPizza(String orderType) {
System.out.println("~使用的是抽象工厂模式~");
// TODO Auto-generated method stub
Pizza pizza = null;
if(orderType.equals("cheese")) {
pizza = new BJCheesePizza();
} else if (orderType.equals("pepper")){
pizza = new BJPepperPizza();
}
return pizza;
}
}
OrderPizza类
/**
* @author 漆剑
* @date 2021-03-27
* @description
*/
public class OrderPizza {
AbsFactory factory;
// 构造器
public OrderPizza(AbsFactory factory) {
setFactory(factory);
}
private void setFactory(AbsFactory factory) {
Pizza pizza = null;
String orderType = ""; // 用户输入
this.factory = factory;
do {
orderType = getType();
// factory 可能是北京的工厂子类,也可能是伦敦的工厂子类
pizza = factory.createPizza(orderType);
if (pizza != null) { // 订购ok
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
} else {
System.out.println("订购失败");
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 "";
}
}
}
客户端调用(以伦敦为例)
/**
* @author 漆剑
* @date 2021-03-27
* @description
*/
public class PizzaStore {
public static void main(String[] args) {
// TODO Auto-generated method stub
//new OrderPizza(new BJFactory());
new OrderPizza(new LDFactory());
}
}
优缺点说明:
1)抽象工厂,采用组合,抽象层级在工厂方法之上,所以抽象工厂里其实经常使用到工厂方法的思想。
2)将工厂抽象成两层,AbsFactory(抽象工厂) 和 具体实现的工厂子类。程序员可以根据创建对象类型使用对应的
工厂子类。这样将单个的简单工厂类变成了工厂簇,更利于代码的维护和扩展。
1、一个调用者想创建一个对象,只要知道其名称就可以了
2、扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以
3、屏蔽产品的具体实现,调用者只关心产品的接口
4、每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度
由于水平有限,本博客难免有不足,恳请各位大佬不吝赐教!