1.工厂模式简介
工厂模式,就是将对象实例化的方法进行提取并封装,放到一个类中进行统一管理维护,达到与主项目降低依赖,降低耦合性。从而提高项目的扩展性和可维护性
假设你去买果汁,直接去果汁店,果汁店会根据你的需求给你做好饮品,直接喝就可以,不用考虑太多,这里的果汁店就类似于一个工厂(或者一个工厂簇),根据你提供的生产出实例(怎么突然想到spring的ioc...)
2.工厂模式的实现方法
常见的工厂模式共三种,主要分为
简单工厂模式(静态工厂模式)
工厂方法模式
抽象工厂模式
2-0:需求(后面用工厂模式进行改进)
完成各种披萨的生产以及订购任务。
1.披萨的种类有很多,例如(GreekPizza,CheesePizza)等
2.披萨的制作工艺复杂(prepare,bake,cut,box)
3.完成pizza店的订购任务
思路:构建一个pizza的抽象类,然后其他pizza去继承该类,达到不同pizza种类的构建。另外构建出orderPizza类,对Pizza进行统一处理
优点:比较容易理解,操作简单
缺点:违反了设计模式的ocp原则,即对扩展开放,对修改关闭。当我们给类增加新功能的时候,尽量不修改代码或者少修改代码
(比如说需要再添加一种pizza种类,要在源代码的基础上修改很多)
UML:
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;
}
}
public class PepperPizza extends Pizza {
@Override
public void prepare() {
System.out.println("制作PeeperPizza,准备原材料中");
}
}
public class GreekPizza extends Pizza {
@Override
public void prepare() {
System.out.println("制作GreekPizza,准备原材料中");
}
}
public class ChessPizza extends Pizza {
@Override
public void prepare() {
System.out.println("制作ChessPizza,准备原材料中");
}
}
//简单工厂模式的上述代码一致
//-------------------------------------------------------------------------
//订购pizza
public class OrderPizza {
public OrderPizza() {
//违背了迪米特原则
Pizza pizza = null;
String orderType;//订购类型
do {
orderType = getType();
if (orderType.equals("greek")) {
pizza = new GreekPizza();
pizza.setName(orderType + " pizza ");
} else if (orderType.equals("cheese")) {
pizza = new ChessPizza();
pizza.setName(orderType + " pizza ");
} else if (orderType.equals("pepper")) {
pizza = new PepperPizza();
pizza.setName(orderType + " pizza ");
} 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 type:");
String str = strin.readLine();
return str;
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
}
//客户端完成订购任务
public class PizzaStore {
public static void main(String[] args) {
OrderPizza pizza = new OrderPizza();
}
}
2-1:简单工厂模式(静态工厂模式)
思路:创建一个工厂类,用来实例化所有对象(pizza实例和上述一致)
UML:
代码演示:
//简单工厂类(静态工厂)
/**
*
* 在一处进行new即可(工厂类) 其他地方直接使用实例 public (static) T createXxx();
*
* !!!定义一个可以实例化对象的类,从而去覆盖掉创建对象的代码(代码的重封装)
* */
//在简单工厂中进行实例的new
public class SimpleFactory {
//使用简单工厂模式,给出预订类型 创建pizza
public static Pizza createPizza(String orderType) {
System.out.println("使用简单工厂模式");
Pizza pizza = null;
if (orderType.equals("greek")) {
pizza = new GreekPizza();
pizza.setName(orderType + " pizza ");
} else if (orderType.equals("cheese")) {
pizza = new ChessPizza();
pizza.setName(orderType + " pizza ");
}
//增加方法只需要更改一处即可
else if (orderType.equals("pepper")) {
pizza = new PepperPizza();
pizza.setName(orderType + " pizza ");
}
return pizza;
}
}
//订购pizza
public class OrderPizza {
private Pizza pizza;
private String orderType;//用户输入
public void setFactory(){
do {
orderType=getType();
pizza = SimpleFactory.createPizza(orderType);
if(pizza != null){
showPizza();
}
}while (true);
}
//展示
public void showPizza() {
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}
//获取类型
private String getType() {
try {
BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
System.out.println("input pizza type:");
String str = strin.readLine();
return str;
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
}
//客户端完成订购任务
public class PizzaStore {
public static void main(String[] args) {
OrderPizza pizza = new OrderPizza();
//制作完毕
pizza.setFactory();
}
}
2-2:工厂方法模式
假设现在增加需求,在订购pizza的时候可以去选择pizza的产地,该如何改进?
1.依旧使用简单工厂模式,创建不同的工厂实体类用来生产不同的pizza
2.使用工厂方法模式
*将pizza项目的实例化方法 即上述SimpleFactory中的createPizza()方法变成抽象方法,在不同的子类中进行实现
工厂方法模式的核心:
如果在实际操作中创建的实例存在父类,子类的形式,可以考虑使用工厂方法模式,定义一个创建子类的抽象方法,由子类决定需要实例的类。工厂方法模式将对象的实例化进行推迟子类
代码演示:
//--------实例(来自不同地区不同口味的pizza)------------------------
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;
}
}
public class BJCheesePizza extends Pizza {
@Override
public void prepare() {
// TODO Auto-generated method stub
setName("北京的奶酪pizza");
System.out.println(" 北京的奶酪pizza 准备原材料");
}
}
public class BJPepperPizza extends Pizza {
@Override
public void prepare() {
// TODO Auto-generated method stub
setName("北京的胡椒pizza");
System.out.println(" 北京的胡椒pizza 准备原材料");
}
}
public class LDCheesePizza extends Pizza{
@Override
public void prepare() {
// TODO Auto-generated method stub
setName("伦敦的奶酪pizza");
System.out.println(" 伦敦的奶酪pizza 准备原材料");
}
}
public class LDPepperPizza extends Pizza{
@Override
public void prepare() {
// TODO Auto-generated method stub
setName("伦敦的胡椒pizza");
System.out.println(" 伦敦的胡椒pizza 准备原材料");
}
}
//--------------------------------------------------------------
public abstract class OrderPizza {
//子类实现的抽象方法
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 "";
}
}
}
//对象的实例化推迟到子类
public class BJOrderPizza extends OrderPizza {
@Override
Pizza createPizza(String orderType) {
Pizza pizza = null;
if(orderType.equals("cheese")) {
//子类new
pizza = new BJCheesePizza();
} else if (orderType.equals("pepper")) {
//子类new
pizza = new BJPepperPizza();
}
// TODO Auto-generated method stub
return pizza;
}
}
//对象的实例化推迟到子类
public class LDOrderPizza extends OrderPizza {
//在子类中进行创建
@Override
Pizza createPizza(String orderType) {
Pizza pizza = null;
if(orderType.equals("cheese")) {
//子类new
pizza = new LDCheesePizza();
} else if (orderType.equals("pepper")) {
//子类new
pizza = new LDPepperPizza();
}
// TODO Auto-generated method stub
return pizza;
}
}
// store
public class PizzaStore {
public static void main(String[] args) {
String loc = "bj";
if (loc.equals("bj")) {
//创建北京口味的各种Pizza
new BJOrderPizza();
} else {
//创建伦敦口味的各种Pizza
new LDOrderPizza();
}
// TODO Auto-generated method stub
}
}
2-3: 抽象工厂模式
介绍:
1.抽象工厂模式可以将简单工厂模式和工厂方法模式进行整合
2.将工厂类抽象为两层,第一层是抽象化的工厂(接口),用于定义工厂的规范,第二层实现具体工厂,生产合适的实例,利于代码的维护和扩展。
UML:
代码实例:
//*********工厂簇*******************8
//一个抽象工厂模式的抽象层(接口)
public interface AbsFactory {
//工厂子类具体实现
public Pizza createPizza(String orderType);
}
public class BJFactory implements AbsFactory {
@Override
public Pizza createPizza(String orderType) {
//开始生产
Pizza pizza = null;
if (orderType.equals("cheese")) {
//子类new
pizza = new BJCheesePizza();
} else if (orderType.equals("pepper")) {
//子类new
pizza = new BJPepperPizza();
}
// TODO Auto-generated method stub
return pizza;
}
}
public class LDFactory implements AbsFactory {
@Override
public Pizza createPizza(String orderType) {
Pizza pizza = null;
if (orderType.equals("cheese")) {
//子类new
pizza = new LDCheesePizza();
} else if (orderType.equals("pepper")) {
//子类new
pizza = new LDPepperPizza();
}
// TODO Auto-generated method stub
return pizza;
}
}
//生产点 调用工厂
public class OrderPizza {
// private AbsFactory factory;
// public void setFactory(AbsFactory factory){
// this.factory = factory;
// }
// 写一个方法,可以获取客户希望订购的披萨种类
//生产pizza 多态
public void productPizza(AbsFactory factory){
Pizza pizza = null;
String orderType; // 订购披萨的类型
do {
orderType = getType();
pizza=factory.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 "";
}
}
}
//*****************实例*********************
public class PizzaStore {
public static void main(String[] args) {
OrderPizza mOrder = new OrderPizza();
//多态
mOrder.productPizza(new BJFactory());
}
}
public class BJPepperPizza extends Pizza {
@Override
public void prepare() {
// TODO Auto-generated method stub
setName("北京的胡椒pizza");
System.out.println(" 北京的胡椒pizza 准备原材料");
}
}
public class LDCheesePizza extends Pizza {
@Override
public void prepare() {
// TODO Auto-generated method stub
setName("伦敦的奶酪pizza");
System.out.println(" 伦敦的奶酪pizza 准备原材料");
}
}
public class LDPepperPizza extends Pizza {
@Override
public void prepare() {
// TODO Auto-generated method stub
setName("伦敦的胡椒pizza");
System.out.println(" 伦敦的胡椒pizza 准备原材料");
}
}
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;
}
}
//销售点
//销售点
public class PizzaStore {
public static void main(String[] args) {
OrderPizza mOrder = new OrderPizza();
//多态
mOrder.productPizza(new BJFactory());
}
}
3.jdk中的工厂模式 Calender
1.在这里截取了部分java.util.calender的源码,能看到Calendar中使用了简单工厂模式的思想,通过getInstance进行实例的创建。
2.根据提供的cal,进行不同实例的初始化。
3.将这里的代码和上述简单工厂的pizza对比,如果pizza的种类再多,与其使用if else if else,不如使用switch来的清晰。
public static Calendar getInstance()
{
return createCalendar(TimeZone.getDefault(), Locale.getDefault(Locale.Category.FORMAT));
}
private static Calendar createCalendar(TimeZone zone,
Locale aLocale)
{
CalendarProvider provider =
LocaleProviderAdapter.getAdapter(CalendarProvider.class, aLocale)
.getCalendarProvider();
if (provider != null) {
try {
return provider.getInstance(zone, aLocale);
} catch (IllegalArgumentException iae) {
// fall back to the default instantiation
}
}
//以此为根据 进行条件判断,从而确定怎样创建实例
Calendar cal = null;
if (aLocale.hasExtensions()) {
String caltype = aLocale.getUnicodeLocaleType("ca");
if (caltype != null) {
switch (caltype) {
case "buddhist":
//实例化
cal = new BuddhistCalendar(zone, aLocale);
break;
//实例化
case "japanese":
cal = new JapaneseImperialCalendar(zone, aLocale);
break;
//实例化
case "gregory":
cal = new GregorianCalendar(zone, aLocale);
break;
}
}
}
//!!!
if (cal == null) {
// If no known calendar type is explicitly specified,
// perform the traditional way to create a Calendar:
// create a BuddhistCalendar for th_TH locale,
// a JapaneseImperialCalendar for ja_JP_JP locale, or
// a GregorianCalendar for any other locales.
// NOTE: The language, country and variant strings are interned.
if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") {
//实例化
cal = new BuddhistCalendar(zone, aLocale);
} else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja"
&& aLocale.getCountry() == "JP") {
//实例化
cal = new JapaneseImperialCalendar(zone, aLocale);
} else {
//实例化
cal = new GregorianCalendar(zone, aLocale);
}
}
return cal;
}
4.总结
tip1:
工厂模式就是将创建实例的方法进行抽离,从而封装为独立的生产类,在这个类中进行各种实例的初始化
tip2:
如果组织架构单一,使用简单工厂即可;
如果组织结构复杂(存在父类或者子类的关系),可以将创建实例的方法进行抽象(类似上述的createPizza()),在子类中具体实现(延迟实例的初始化)【抽象方法】
或者将整个工厂进行抽象,作为工厂模板(AbsFactory),从而实例化多个子工厂,聚合或者组合到其他类中。