【设计模式】第四篇 - 简单工厂
发布于: 刚刚
1,前言
上一篇我们说了单例,按照难度来递进,这次轮到工厂了
工厂计划分三部分说:简单工厂,工厂方法,抽象工厂
三部分争取使用相似或有关联的例子进行递进式的讲解
这样一来,既可以实现三种工厂的对比,又可以说明根据需求变化工厂模式逐渐演变的过程
简单工厂实际并不属于一种设计模式,但这里我们就当成一种设计模式来说,主要是给后边两个模式做铺垫
复制代码
2,场景
外卖有各种饭,工厂这部分就用这些饭来做例子,将工厂模式用于制作各种饭的过程
简单工厂:
餐厅制作鸡肉饭,烤肉饭,牛肉饭
制作流程为:准备,烹饪,摆放,打包
复制代码
3,不使用工厂的代码
简单的写一个类,根据传入的类型做饭
package com.brave.food;
import com.brave.food.simplefactory.rice.BarbecueRice;
import com.brave.food.simplefactory.rice.BeefRice;
import com.brave.food.simplefactory.rice.ChickenRice;
import com.brave.food.simplefactory.rice.Rice;
/**
* 餐厅
* 不使用设计模式的餐厅
* @author Brave
*
*/
public class Restaurant {
public void orderRice(String type){
Rice rice = null;
if(type.equals("BarbecueRice")){
rice = new BarbecueRice();
} else if(type.equals("BeefRice")){
rice = new BeefRice();
} else if(type.equals("ChickenRice")){
rice = new ChickenRice();
}
System.out.println("-----------"+type+"----------");
rice.prepare();
rice.cook();
rice.set();
rice.box();
}
}
复制代码
完善剩余代码:
饭的抽象类:
package com.brave.food.simplefactory.rice;
/**
* Rice:饭抽象类
* 各种饭继承此抽象类
* @author Brave
*
*/
public abstract class Rice {
// 准备
public void prepare(){
System.out.println("准备");
}
// 烹饪
public void cook(){
System.out.println("烹饪");
}
// 摆放
public void set(){
System.out.println("摆放");
}
// 打包
public void box(){
System.out.println("打包");
}
}
复制代码
各种饭:继承上边饭的抽象类:
package com.brave.food.simplefactory.rice;
public class ChickenRice extends Rice {
@Override
public void prepare() {
System.out.println("鸡肉饭-准备");
}
@Override
public void cook() {
System.out.println("鸡肉饭-烹饪");
}
@Override
public void set() {
System.out.println("鸡肉饭-摆放");
}
@Override
public void box() {
System.out.println("鸡肉饭-打包");
}
}
复制代码
客户端:
package com.brave.food;
/**
* 客户端
* 不使用设计模式的客户端
* @author Brave
*
*/
public class Client {
public static void main(String[] args) {
Restaurant restaurant = new Restaurant();
restaurant.orderRice("BarbecueRice");
restaurant.orderRice("BeefRice");
restaurant.orderRice("ChickenRice");
}
}
复制代码
4,问题和分析
首先,这种写法简单明了,在实际项目中应用也很多,并没有什么问题
最大的问题不是代码本身,而是需求的变化
问题:
Restaurant类,依赖了所有"饭"的具体类(BarbecueRice,BeefRice,ChickenRice)
当饭的"产品种类"频繁变化时,就需要对这个类进行频繁修改,这个修改可能造成orderRice方法问题,从而影响到其他"饭"的创建
违反了几个设计原则:
1,依赖倒置原则:
依赖于抽象,不要依赖具体类,相比于"针对接口编程,不针对实现编程"来说,这里更强调抽象
不能让高层组件依赖低层组件,并且,无论高层或是底层组件,两者都应依赖于抽象
Restaurant是高层组件,各种"饭"的实现是低层组件,Restaurant依赖了所有"饭"的实现
2,”开放-关闭”原则:
对拓展开放,对修改关闭
频繁维护饭的"产品种类",无法让orderRice()对修改关闭
所以我们应该找出变化的部分,将他们从不变的部分中分离出来
复制代码
5,简单工厂
将频繁变化的部分创建为一个简单工厂类
package com.brave.food.simplefactory;
import com.brave.food.simplefactory.rice.BarbecueRice;
import com.brave.food.simplefactory.rice.BeefRice;
import com.brave.food.simplefactory.rice.ChickenRice;
import com.brave.food.simplefactory.rice.Rice;
/**
* 简单工厂
* 用于创建具体对象
* @author Brave
*
*/
public class SimpleRiceFactory {
/**
* 根据类型创建对应的"饭"对象
* @param type
* @return
*/
public Rice createRice(String type){
Rice rice = null;
if(type.equals("BarbecueRice")){
rice = new BarbecueRice();
} else if(type.equals("BeefRice")){
rice = new BeefRice();
} else if(type.equals("ChickenRice")){
rice = new ChickenRice();
}
return rice;
}
}
复制代码
修改餐厅的构造方法,使用工厂进行饭的实例化:
package com.brave.food.simplefactory;
import com.brave.food.simplefactory.rice.Rice;
/**
* 餐厅
* @author Brave
*
*/
public class Restaurant {
SimpleRiceFactory factory;
public Restaurant(SimpleRiceFactory factory){
this.factory = factory;
}
public void orderRice(String type){
Rice rice;
rice = factory.createRice(type);
System.out.println("-----------"+type+"----------");
rice.prepare();
rice.cook();
rice.set();
rice.box();
}
}
复制代码
客户端:
package com.brave.food.simplefactory;
/**
* 客户端:
* 仅仅依赖SimpleRiceFactory, Restaurant两个类
* 将各种"饭"的制作流程和实例化过程封装起来
* 当有新的"饭"加入时无需修改原有客户端代码,只需添加调用即可
* @author Brave
*
*/
public class Client {
public static void main(String[] args) {
// 创建简单工厂-肯定类型创建"饭"对象
SimpleRiceFactory simpleFactory = new SimpleRiceFactory();
// 注入工厂创建餐厅-使餐厅创建"饭"对象的过程受工厂对象实现的控制
Restaurant restaurant = new Restaurant(simpleFactory);
// 向指定了工厂对象的餐厅下单
restaurant.orderRice("BarbecueRice");
restaurant.orderRice("BeefRice");
restaurant.orderRice("ChickenRice");
}
}
复制代码
6,简单工厂分析
简单工厂将变化的部分提取出来
Restaurant依赖Rice(抽象类),SimpleRiceFactory(简单工厂)
orderRice()仅需要消费简单工厂返回的对象即可
当饭的"产品种类"频繁变化时,Restaurant类无需修改
简单工厂的优点:
去除了客户端与具体产品的依赖,封装了对象的创建过程
简单工厂的的不足:
工厂类中包含了所有实例创建的逻辑,一旦工厂出问题,所有客户端都会有问题
简单工厂的产品是基于共同的抽象类或接口创建的,所以当产品种类增加时(新的抽象类加入),工厂类就需要判断创建何种接口的产品,和创建何种种类的产品相互混淆,违背了单一职责原则,导致系统丧失灵活性和可维护性
新增一个产品时,无法避免的,必须修改工厂类,但可以利用反射在一定程度上解决(仅限于产品类的构造及初始化相同的场景),所以很难满足严格意义上的"开放-关闭"原则
简单工厂还有一种实现方式是使用静态工厂方式,静态工厂虽然不需要实例化具体对象就可以使用,但丧失了通过继承改变行为的能力
复制代码
7,利用反射弥补简单工厂拓展性
利用反射弥补简单工厂拓展性,从而在某种程度上实现"开放-关闭"原则
复制代码
1,修改工厂类,通过反射创建对象
package com.brave.food.simplefactory.reflection;
import com.brave.food.simplefactory.rice.Rice;
/**
* 简单工厂-反射实现
* 利用反射弥补简单工厂拓展性,从而在某种程度上实现”开放-关闭”原则
*
* @author Brave
*
*/
public class SimpleRiceFactory {
/**
* 根据类型创建对应的"饭"对象
* @param c
* @return
*/
public Rice createRice(Class c){
Rice rice = null;
try {
rice = (Rice) Class.forName(c.getName()).newInstance();
} catch (InstantiationException e) {
System.out.println("不支持抽象类或接口");
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
System.out.println("没有足够权限,即不能访问私有对象");
} catch (ClassNotFoundException e) {
System.out.println("类不存在");
e.printStackTrace();
}
return rice;
}
}
复制代码
修改调用:
package com.brave.food.simplefactory.reflection;
import com.brave.food.simplefactory.rice.Rice;
/**
* 餐厅
* @author Brave
*
*/
public class Restaurant {
SimpleRiceFactory factory;
public Restaurant(SimpleRiceFactory factory){
this.factory = factory;
}
public void orderRice(Class c){
Rice rice;
rice = factory.createRice(c);
System.out.println("-----------"+c+"----------");
rice.prepare();
rice.cook();
rice.set();
rice.box();
}
}
复制代码
package com.brave.food.simplefactory.reflection;
import com.brave.food.simplefactory.rice.BarbecueRice;
import com.brave.food.simplefactory.rice.BeefRice;
import com.brave.food.simplefactory.rice.ChickenRice;
/**
* 客户端:
* 使用简单工厂-反射的方式实现对象的创建
* 当有新的"饭"加入时,只需添加新的类,无需修改工厂类
* 利用反射弥补简单工厂拓展性,从而在某种程度上实现”开放-关闭”原则
* @author Brave
*
*/
public class Client {
public static void main(String[] args) {
// 创建简单工厂-肯定类型创建"饭"对象
SimpleRiceFactory simpleFactory = new SimpleRiceFactory();
// 注入工厂创建餐厅-使餐厅创建"饭"对象的过程受工厂对象实现的控制
Restaurant restaurant = new Restaurant(simpleFactory);
// 向指定了工厂对象的餐厅下单
restaurant.orderRice(BarbecueRice.class);
restaurant.orderRice(BeefRice.class);
restaurant.orderRice(ChickenRice.class);
}
}
复制代码
运行结果:
-----------class com.brave.food.simplefactory.rice.BarbecueRice----------
烤肉饭-准备
烤肉饭-烹饪
烤肉饭-摆放
烤肉饭-打包
-----------class com.brave.food.simplefactory.rice.BeefRice----------
牛肉饭-准备
牛肉饭-烹饪
牛肉饭-摆放
牛肉饭-打包
-----------class com.brave.food.simplefactory.rice.ChickenRice----------
鸡肉饭-准备
鸡肉饭-烹饪
鸡肉饭-摆放
鸡肉饭-打包
复制代码
8,简单工厂在 JDK 中的应用
简单工厂在JDK中最典型的应用就是JDBC
把关系型数据库认为是抽象产品
MySQL,Oracle是具体产品
DriverManager是工厂类
应用程序通过JDBC接口使用关系型数据库,不需关心使用哪种数据库
直接使用DriverManager的静态方法去得到该数据库的Connection即可
复制代码
package com.brave.simplefactory.jdk;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
/**
* 简单工厂在JDK中的使用
*
* @author Brave
*
*/
public class JDBC {
public static void main(String[] args) {
Connection conn = null;
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1/student");
PreparedStatement ps = conn.prepareStatement("select * from mysql.test");
ps.execute();
} catch (SQLException ex) {
System.out.println("Execute query failed " + ex);
} catch (ClassNotFoundException e) {
System.out.println("Load mysql driver failed " + e);
} finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
}
}
}
}
}
复制代码
划线
评论
复制
发布于: 刚刚阅读数: 3
Brave
关注
还未添加个人签名 2018.12.13 加入
还未添加个人简介
评论