工厂模式主要是为创建对象提供了接口。工厂模式分为三类:
1. 简单工厂模式(Simple Factory)
2. 工厂方法模式(Factory Method)
3. 抽象工厂模式(Abstract Factory)
三个设计模式名字中都含有“工厂”二字,其含义是使用工厂(一个或一系列方法)去生产产品(一个或一系列类的实例)。
另外,有时候,我们常常会将生产产品的一个或一系列方法封装到一个类中,我习惯把这个类叫做“工厂类”;而被实例化的类称作“产品类”。
下面是使用工厂模式的两种情况:
1.在编码时不能预见需要创建哪种类的实例。
2.系统不应依赖于产品类实例如何被创建、组合和表达的细节。
一:Simple Factory
简单工厂模式:工厂类(SimpleFactory)拥有一个工厂方法(create),接受了一个参数,通过不同的参数实例化不同的产品类。
有4个角色
工厂类角色:是具体产品类角色直接调用者。
抽象产品角色:接口或抽象类,负责具体产品角色的定义,及与客户端的交互。
具体产品角色:被工厂类创建的对象,也是客户端实际操作对象。
客户端:调用工厂类产生实例,并调用实例的方法进行相应工作。
抽象产品接口:
package cn.design.factory; public interface DBDriver { public void dbConn(String ip); public void dbClose(); public String dbOper(); }
具体产品接口:
package cn.design.factory; public class MySqlDriver implements DBDriver{ @Override public void dbConn(String ip) { // TODO Auto-generated method stub System.out.println("已成功连接到MySql数据库! 数据库地址为"+ip); } @Override public void dbClose() { // TODO Auto-generated method stub System.out.println("MySql数据库连接已关闭!"); } @Override public String dbOper() { // TODO Auto-generated method stub String s="正在对MySql数据库进行操作"; System.out.println("正在对MySql数据库进行操作"); return s; } }
package cn.design.factory; public class OracleDriver implements DBDriver{ @Override public void dbConn(String ip) { // TODO Auto-generated method stub System.out.println("已连接到Oracle数据库 数据库地址为 "+ip); } @Override public void dbClose() { // TODO Auto-generated method stub System.out.println("已关闭Oracle数据库连接"); } @Override public String dbOper() { // TODO Auto-generated method stub String s="正在对Oracle数据库进行操作"; System.out.println("正在对Oracle数据库进行操作"); return s; } }
package cn.design.factory; public class DB2Driver implements DBDriver{ @Override public void dbConn(String ip) { // TODO Auto-generated method stub System.out.println("准备连接DB2数据库: ip地址为:"+ ip); } @Override public void dbClose() { // TODO Auto-generated method stub System.out.println("关闭DB2链接"); } @Override public String dbOper() { // TODO Auto-generated method stub System.out.println("正在对DB2数据库进行操作"); return null; } }
工厂类:
package cn.design.factory; /** * 联想到之前写过的多态相关代码 * 继承关系 * 重写父类的方法 * 父类引用指向子类对象 * @author 翎野君 * */ public class SimpleFactory { public static DBDriver getDBDriver(String dbType){ switch(dbType){ case "oracle": return new OracleDriver(); case "mysql": return new MySqlDriver(); case "db2": return new DB2Driver(); default: return new MySqlDriver(); } } public static void main(String[] args) { DBDriver db=SimpleFactory.getDBDriver("db2"); db.dbConn("127.0.0.1"); db.dbOper(); db.dbClose(); } }
优点:
(1)很明显,简单工厂的特点就是“简单粗暴”,通过一个含参的工厂方法,我们可以实例化任何产品类,上至飞机火箭,下至土豆面条,无所不能。所以简单工厂有一个别名:上帝类。
缺点:
(1)任何”东西“的子类都可以被生产,负担太重。当所要生产产品种类非常多时,工厂方法的代码量可能会很庞大。
(2)在遵循开闭原则(对拓展开放,对修改关闭)的条件下,简单工厂对于增加新的产品,无能为力。因为增加新产品只能通过修改工厂方法来实现。
二:Factory Method
工厂方法是针对每一种产品提供一个工厂类。通过不同的工厂实例来创建不同的产品实例。
工厂方法解决了上述简单工厂上述的两个缺点。
工厂方法由一下四部分组成:
1、抽象工厂角色:这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。在java中它由抽象类或者接口来实现。
2、具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。在java中它由具体的类来实现。
3、抽象产品角色:它是具体产品继承的父类或者是实现的接口。在java中一般有抽象类或者接口来实现。
4、具体产品角色:具体工厂角色所创建的对象就是此角色的实例。在java中由具体的类来实现。
首先完全实现‘开-闭 原则’,实现了可扩展。其次更复杂的层次结构,可以应用于产品结果复杂的场合。
package cn.design.factory; public class FactoryMethod{ /** * 工厂模式最后对外开放给使用者的就是一个一个的工厂类(Factory) */ public static void main(String[] args) { MysqlFactory mf=new MysqlFactory(); OracleFactory of=new OracleFactory(); mf.getDBConn().getDriver(); mf.getDBConn().getUrl(); mf.getDBConn().getUP(); mf.getDBConn().connDB(); of.getDBConn().getDriver(); of.getDBConn().getUrl(); of.getDBConn().getUP(); of.getDBConn().connDB(); } } /** * 抽象的数据库连接角色 * @author 翎野君 * */ interface ConnDBInterface{ public void getDriver(); public void getUrl(); public void getUP(); public void connDB(); } /** * 抽象工厂角色 * @author 翎野君 * */ interface FactoryMethodInterface{ public ConnDBInterface getDBConn(); } /** * 专门连接Mysql的工厂 * @author 翎野君 * */ class MysqlFactory implements FactoryMethodInterface{ @Override public ConnDBInterface getDBConn() { // TODO Auto-generated method stub return new ConnMysql(); } } /** * 专门连接Oracle的工厂 */ class OracleFactory implements FactoryMethodInterface{ @Override public ConnDBInterface getDBConn() { // TODO Auto-generated method stub return new ConnOracle(); } } /** * 具体的连接Mysql的实现类 * @author 翎野君 * */ class ConnMysql implements ConnDBInterface{ @Override public void getDriver() { // TODO Auto-generated method stub System.out.println("加载mysql数据库驱动"); } @Override public void getUrl() { // TODO Auto-generated method stub System.out.println("获取mysql连接地址127.0.0.1"); } @Override public void getUP() { // TODO Auto-generated method stub System.out.println("获取mysql的用户名:root 密码:password"); } @Override public void connDB() { // TODO Auto-generated method stub System.out.println("成功连接到mysql数据库"); } } /** * 具体的连接Oracle的实现类 * @author 翎野君 * */ class ConnOracle implements ConnDBInterface{ @Override public void getDriver() { // TODO Auto-generated method stub System.out.println("加载oracle数据库驱动"); } @Override public void getUrl() { // TODO Auto-generated method stub System.out.println("获取oracle连接地址127.0.0.1"); } @Override public void getUP() { // TODO Auto-generated method stub System.out.println("获取oracle的用户名:root 密码:password"); } @Override public void connDB() { // TODO Auto-generated method stub System.out.println("成功连接到oracle数据库"); } }
优点:
(1)工厂方法模式就很好的减轻了工厂类的负担,把某一类/某一种东西交由一个工厂生产;(对应简单工厂的缺点1)
(2)同时增加某一类”东西“并不需要修改工厂类,只需要添加生产这类”东西“的工厂即可,使得工厂类符合开放-封闭原则。
缺点:
(1)相比简单工厂,实现略复杂。
(2)对于某些可以形成产品族的情况处理比较复杂。
对于缺点(2),我们可以借用抽象工厂来实现。
三:Abstract Factory
抽象工厂是应对产品族概念的
例如,汽车可以分为轿车、SUV、MPV等,也分为奔驰、宝马等。我们可以将奔驰的所有车看作是一个产品族,而将宝马的所有车看作是另一个产品族。分别对应两个工厂,一个是奔驰的工厂,另一个是宝马的工厂。与工厂方法不同,奔驰的工厂不只是生产具体的某一个产品,而是一族产品(奔驰轿车、奔驰SUV、奔驰MPV)。“抽象工厂”的“抽象”指的是就是这个意思。
上边的工厂方法模式是一种极端情况的抽象工厂模式(即只生产一种产品的抽象工厂模式),而抽象工厂模式可以看成是工厂方法模式的一种推广。
来看看抽象工厂模式的各个角色(和工厂方法的一样)
抽象类
package cn.design.factory; public abstract class AbstractBenz { public abstract void start(); public abstract void run(); public abstract void stop(); }
具体类
package cn.design.factory; public class BenzSport extends AbstractBenz{ @Override public void start() { // TODO Auto-generated method stub System.out.println("奔驰跑车启动"); } @Override public void run() { // TODO Auto-generated method stub System.out.println("奔驰跑车行驶"); } @Override public void stop() { // TODO Auto-generated method stub System.out.println("奔驰跑车熄火"); } public void game(){ System.out.println("纽伯格林赛道比赛!!!"); } }
package cn.design.factory; public class BenzMpv extends AbstractBenz{ @Override public void start() { // TODO Auto-generated method stub System.out.println("奔驰保姆车启动"); } @Override public void run() { // TODO Auto-generated method stub System.out.println("奔驰保姆车行驶"); } @Override public void stop() { // TODO Auto-generated method stub System.out.println("奔驰保姆车熄火"); } public void sleep(){ System.out.println("在保姆车中睡觉"); } }
抽象工厂类
package cn.design.factory; public abstract class AbstractFactory { public abstract AbstractBenz getBenzSport(); public abstract AbstractBenz getBenzMpv(); }
具体工厂类
package cn.design.factory; public class BenzFactory extends AbstractFactory{ @Override public BenzSport getBenzSport() { // TODO Auto-generated method stub return new BenzSport(); } @Override public BenzMpv getBenzMpv() { // TODO Auto-generated method stub return new BenzMpv(); } public static void main(String[] args) { BenzFactory bf=new BenzFactory(); bf.getBenzSport().game(); bf.getBenzMpv().run(); } }
优点:针对产品族;
缺点:针对产品族。
所以,只有对应产品族的情况下,才需要使用抽象工厂模式。
区别
简单工厂 : 用来生产同一等级结构中的任意产品。(不支持拓展增加产品)
工厂方法 :用来生产同一等级结构中的固定产品。(支持拓展增加产品)
抽象工厂 :用来生产不同产品族的全部产品。(不支持拓展增加产品;支持增加产品族)