设计模式3-工厂模式
工厂模式分为三种: 简单工厂模式(也叫静态工厂模式)、工厂方法模式、抽象工厂模式。以下会分别介绍这三种工厂模式。
一、概念
创建型模式
工厂模式提供了一种创建对象的最佳方式。它最关心的是最终创建的对象,而不关心创建的过程。
功能:
- 实例化对象,用工厂方法代替new,实现了创建者和调用者的分离;
- 将选择实现类、创建对象统一管理和控制,从而将调用者跟我们的实现类解藕。
二、分类
1、简单工厂模式(静态工厂模式)
用来产生同一等级结构中的任意产品。对于增加新的产品,需要修改已有代码。
效果:
- 工厂类一般使用静态方法,通过接收的参数来返回不同的对象实例;
- 增加产品必须修改代码(违反开闭原则OCP:修改关闭,对扩展开放);
示例(以动物为例):
1 public interface Animal 2 { 3 void eat(); //吃东西 4 void cry(); //发出声音 5 }
有两种动物猫和狗:
1 public class Cat implement Animal 2 { 3 public void eat() 4 { 5 System.out.println("cat eat fish."); 6 } 7 8 public void cry() 9 { 10 System.out.println("cat cry:miaomiao."); 11 } 12 13 }
1 public class Dog implement Animal 2 { 3 public void eat() 4 { 5 System.out.println("dog eat meat."); 6 } 7 8 public void cry() 9 { 10 System.out.println("dog cry:汪汪."); 11 } 12 13 }
有个宠物店,接收各种动物:
1 public class PetShop 2 { 3 public static Animal getAnimal(String name) 4 { 5 if("cat".equalsIgnoreCase(name) 6 { 7 return new Cat(); 8 } 9 else if("dog".equalsIgnoreCase(name) 10 { 11 return new Dog(); 12 } 13 else 14 { 15 ....... 16 } 17 } 18 }
调用示例:
public static void main(String[] args) { Animal cat = PetShop.getAnimal("cat"); cat.eat(); Animal dog = PetShop.getAnimal("dog"); dog.eat(); }
从示例中就可以看出,自己无需去new对象,通过PetShop就可以获取对象,这样使用方就和产品之间就降低了耦合度;
代码模块职责更明确了,有专门的消费模块,有专门的生产模块。
但若增加另一种动物,则必须修改PetShop中的代码,每增加一种都必须再PetShop中增加一个else if, 这样很是不便,对此我们可以将PetShop改为通过反射的方式获取对象:
1 public class PetShop 2 { 3 public static Animal getAnimal(String namePath) throws Exception 4 { 5 Class<?> c = Class.forName(namePath); 6 return (Animal)c.newInstance(); 7 } 8 }
调用的地方改为:
1 public static void main(String[] args) throws Exception 2 { 3 Animal dog = PetShop.getAnimal("com.frieda.animalFactory.Dog"); 4 dog.eat(); 5 Animal cat = PetShop.getAnimal("com.frieda.animalFactory.Cat"); 6 cat.cry(); 7 }
但这样做的弊端是,项目重构,类路径,包路径改变,这样更改的地方有点多;但可以通过将所有的类路径放入inerface中后者properties文件或者xml文件中,后期遇到修改路径的, 直接修改改文件即可。
从设计模式的角度讲,这么修改也有很大的优点。现在不管我新增还是删除动物,宠物店(类工厂)都不用变了,只需要告诉工厂我需要哪种动物就够了,工厂自然会给调用者返回。这种写法,也是Spring的基础。
2、工厂方法模式
用来产生同一等级结构中的固定产品。支持增加任意产品。
效果:
- 避免简单工厂的缺点,但不完全满足OCP;
- 定义一个创建产品对象的工厂接口,将实际创建推迟到子类中(简单工厂中的具体工厂类拆成:抽象工厂类层+具体的工厂类层,即产品抽象,工厂也抽象);
- 简单工厂模式VS工厂方法模式: i. 结构复杂度:显然简单工厂模式占优,简单工厂模式只要一个工厂,而工厂方法模式的工厂类随着产品类个数增加而增加。
- ii. 代码复杂度:代码复杂度与结构复杂度相反,简单工厂模式的工厂类随着产品增加需要增加更多方法(代码),而工厂方法模式每个具体工厂类只完成单一任务,代码简单。
- iii. 客户端编程难度:工厂方法模式虽然满足了OCP,但客户端编码中需要对工厂实例化,而简单工厂模式的工厂类是一个静态类。
- iv. 管理上的难度:工厂方法模式需要维护的工厂类过多,而简单工厂模式只有一个。
- 设计理论建议使用工厂方法模式,但实践中往往采用的是简单工厂模式。
借用下他人的图来看下工厂方法模式:
示例:
Car.java
1 public interface Car { 2 3 void run(); 4 5 }
CarFactory.java
1 public interface CarFactory { 2 3 Car createCar(); 4 5 }
Audi.java
1 public class Audi implements Car { 2 3 @Override 4 public void run() { 5 System.out.println("奥迪在跑!"); 6 } 7 8 }
AudiFactory.java
1 public class AudiFactory implements CarFactory { 2 3 @Override 4 public Car createCar() { 5 return new Audi(); 6 } 7 8 }
Jeep.java
1 public class Jeep implements Car { 2 3 @Override 4 public void run() { 5 System.out.println("吉普在跑!"); 6 } 7 8 }
JeepFactory.java
1 public class JeepFactory implements CarFactory { 2 3 @Override 4 public Car createCar() { 5 return new Jeep(); 6 } 7 8 }
调用示例:
1 public class Client { 2 3 public static void main(String[] args) { 4 Car car1 = new AudiFactory().createCar(); 5 Car car2 = new JeepFactory().createCar(); 6 car1.run(); 7 car2.run(); 8 } 9 10 }
3、抽象工厂模式
用来生产不同产品族的全部产品。对于增加新的产品,无能为力:支持增加产品族。
效果:
抽象工厂模式是工厂方法模式的升级版本,在有多个业务品种,业务分类时,通过抽象共产模式产生需要的对象时一种非常好的解决方式。
示例:
Shape,java(interface)
public interface Shape { void draw(); }
Rectangle.java
public class Rectangle implements Shape { @Override public void draw() { System.out.println("Inside Rectangle::draw() method."); } }
Square,java
public class Square implements Shape { @Override public void draw() { System.out.println("Inside Square::draw() method."); } }
Circle.java
public class Circle implements Shape { @Override public void draw() { System.out.println("Inside Circle::draw() method."); } }
Color.java(interface)
public interface Color { void fill(); }
Red.java
public class Red implements Color { @Override public void fill() { System.out.println("Inside Red::fill() method."); } }
Green.java
public class Green implements Color { @Override public void fill() { System.out.println("Inside Green::fill() method."); } }
Blue.java
public class Blue implements Color { @Override public void fill() { System.out.println("Inside Blue::fill() method."); } }
为 Color 和 Shape 对象创建抽象类来获取工厂。
AbstractFactory.java
public abstract class AbstractFactory { public abstract Color getColor(String color); public abstract Shape getShape(String shape) ; }
创建扩展了 AbstractFactory 的工厂类,基于给定的信息生成实体类的对象。
ShapeFactory.java
public class ShapeFactory extends AbstractFactory { @Override public Shape getShape(String shapeType){ if(shapeType == null){ return null; } if(shapeType.equalsIgnoreCase("CIRCLE")){ return new Circle(); } else if(shapeType.equalsIgnoreCase("RECTANGLE")){ return new Rectangle(); } else if(shapeType.equalsIgnoreCase("SQUARE")){ return new Square(); } return null; } @Override public Color getColor(String color) { return null; } }
ColorFactory.java
public class ColorFactory extends AbstractFactory { @Override public Shape getShape(String shapeType){ return null; } @Override public Color getColor(String color) { if(color == null){ return null; } if(color.equalsIgnoreCase("RED")){ return new Red(); } else if(color.equalsIgnoreCase("GREEN")){ return new Green(); } else if(color.equalsIgnoreCase("BLUE")){ return new Blue(); } return null; } }
创建一个工厂创造器/生成器类,通过传递形状或颜色信息来获取工厂。
public class FactoryProducer { public static AbstractFactory getFactory(String choice){ if(choice.equalsIgnoreCase("SHAPE")){ return new ShapeFactory(); } else if(choice.equalsIgnoreCase("COLOR")){ return new ColorFactory(); } return null; } }
使用 FactoryProducer 来获取 AbstractFactory,通过传递类型信息来获取实体类的对象。
AbstractFactoryPatternDemo.java
public class AbstractFactoryPatternDemo { public static void main(String[] args) { //获取形状工厂 AbstractFactory shapeFactory = FactoryProducer.getFactory("SHAPE"); //获取形状为 Circle 的对象 Shape shape1 = shapeFactory.getShape("CIRCLE"); //调用 Circle 的 draw 方法 shape1.draw(); //获取形状为 Rectangle 的对象 Shape shape2 = shapeFactory.getShape("RECTANGLE"); //调用 Rectangle 的 draw 方法 shape2.draw(); //获取形状为 Square 的对象 Shape shape3 = shapeFactory.getShape("SQUARE"); //调用 Square 的 draw 方法 shape3.draw(); //获取颜色工厂 AbstractFactory colorFactory = FactoryProducer.getFactory("COLOR"); //获取颜色为 Red 的对象 Color color1 = colorFactory.getColor("RED"); //调用 Red 的 fill 方法 color1.fill(); //获取颜色为 Green 的对象 Color color2 = colorFactory.getColor("Green"); //调用 Green 的 fill 方法 color2.fill(); //获取颜色为 Blue 的对象 Color color3 = colorFactory.getColor("BLUE"); //调用 Blue 的 fill 方法 color3.fill(); } }
上述示例结构如下:
三、工厂模式在Java中的应用及解读
简单工厂模式在Java中的应用:
线程池
ThreadPoolExecutor类中有四个构造方法
public class ThreadPoolExecutor extends AbstractExecutorService { ..... public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, BlockingQueue<Runnable> workQueue); public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory); public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, BlockingQueue<Runnable> workQueue,RejectedExecutionHandler handler); public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler); ... }
从构造方法的传参看到需要很多参数才能创建对象,但这里的部分参数尤其是后面3个参数基本上用默认值,而不需要每次传入。
再看下线程池的工厂模式(都是使用静态工厂模式创建对象)
Executors.newCachedThreadPool(); //创建一个无界限缓冲池,缓冲池容量大小为Integer.MAX_VALUE Executors.newSingleThreadExecutor(); //创建容量为1的缓冲池 Executors.newFixedThreadPool(int); //创建固定容量大小的缓冲池
具体实现如下:
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); } public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); } public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); }
是不是都已经传入一些默认值,这让我们无需再思考在构造函数中应该传入什么值而苦恼,而直接通过工厂模式获取一个对象。
工厂方法模式在Java中的应用:
ThreadFactory,一个生产线程的接口;
public interface ThreadFactory { /** * Constructs a new {@code Thread}. Implementations may also initialize * priority, name, daemon status, {@code ThreadGroup}, etc. * * @param r a runnable to be executed by new thread instance * @return constructed thread, or {@code null} if the request to * create a thread is rejected */ Thread newThread(Runnable r); }
具体的线程工厂可以implements这个接口并实现newThread(Runnable r)方法,来生产具体线程工厂想要生产的线程。JDK在Executors给开发者提供了一个静态内部类DefaultThreadFactory,当然开发者也可以自行实现这个接口,写自定义的线程工厂。
抽象工厂模式在Java中的应用:
java.sql.Connection
public interface Connection { //提供一个执行对象 Statement createStatement() throws SQLException; //提供一个支持预编译的执行对象 PreparedStatement prepareStatement(String sql) throws SQLException; //提供一个支持存储过程的执行对象 CallableStatement prepareCall(String sql) throws SQLException; }
可以看的出来Connection就是一个经典的抽象工厂,而Statement,PreparedStatement,CallableStatement是这个抽象工厂提供的三个抽象产品,其中Driver起到Client的作用我们只需要把Driver注册进DriverManager就可以为我们生成需要的Connection每次操作数据库只需要使用java提供的这套接口就可以而不需要考虑我们使用的是什么SQL数据库(不考虑特殊SQL语法的情况下)。
这些抽象工厂与抽象产品均由对应的数据库驱动实现,下面用MySQL与Oracle的驱动进行举例。
JDBC抽象工厂UML图