包含的对象
属于创建型设计模式,需要生成的对象叫做产品 ,生成对象的地方叫做工厂 。
使用场景
在任何需要生成复杂对象的地方,都可以使用工厂方法模式。
直接用new可以完成的,不需要用工厂模式
简单静态工厂:
- 先创建一个抽象类
package cn.itcast.factory;
//产品的抽象类,起到分类的作用
public abstract class IBuns {
/*
* 描述每种包子是什么味道的.
*/
public abstract void desc();
}
- 再创建3个具体的产品类
第一个产品
package cn.itcast.factory;
//具体的产品类
public class TJBuns extends IBuns{
@Override
public void desc() {
System.out.println("天津包子-狗不理,闻名天下!");
}
}
第二个产品
package cn.itcast.factory;
public class BJBuns extends IBuns{
@Override
public void desc() {
System.out.println("北京灌汤包-皮薄肉多!");
}
}
第三个产品
package cn.itcast.factory;
public class SCBuns extends IBuns{
@Override
public void desc() {
System.out.println("四川包子-味在辣椒!");
}
}
- 简单静态工厂的创建
package cn.itcast.factory;
//简单工厂类-就把他看成包子铺
public class SimpleBunsFactory {
//开始点包子-我们要看菜单
private static final int TYPE_TJ=1;
private static final int TYPE_BJ=2;
private static final int TYPE_SC=3;
public static IBuns createBuns(int type) {
switch (type) {
case TYPE_TJ:
return new TJBuns();
case TYPE_BJ:
return new BJBuns();
case TYPE_SC:
default:
return new SCBuns();
}
}
public static void main(String[] args) {
//简单工厂模式
IBuns buns = SimpleBunsFactory.createBuns(TYPE_TJ);
buns.desc();
}
}
特点
1.它是一个具体的类,非接口的抽象类,.有一个重要的create方法.利用if或者switch创建产品并返回.
2.create()方法通常都是静态的,所以称为静态工厂.
缺点:
1.扩展性差(加别的包子,还要修改工厂类方法)
2.不同的产品需要不同额外参数的时候不支持.光一个type,所有的包子全部用的到,别的就不好说了.
基于反射实现的简单工厂
Class.forname(clz.getName()).newInstance()实现工厂模式
如下:
package cn.itcast.reflectFactory;
import cn.itcast.staticfactory.BJBuns;
import cn.itcast.staticfactory.IBuns;
import cn.itcast.staticfactory.TJBuns;
public class ReflectFactory {
//传入Class实例化包子产品类
@SuppressWarnings("unchecked")
public static <T extends IBuns> T createBuns(Class<T> clz){
T result =null;
try {
result = (T)Class.forName(clz.getName()).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
//点包子就行了
public static void main(String[] args) {
TJBuns tJBun = ReflectFactory.createBuns(TJBuns.class);
tJBun.desc();
BJBuns bJBun = ReflectFactory.createBuns(BJBuns.class);
bJBun.desc();
}
}
特点:
1.他也是一个具体的类,非接口抽象类.但他的create()方法,是利用反射机制生成对象返回,好处是增加一种产品时,不需要修改create()的代码。
2.缺点:就是不同的产品需要不同的额外参数的时候不支持.
多方法工厂
特点:多方法的工厂模式为不同产品,提供不同的生产方法.
使用时,需要哪种产品就调用该种产品的方法,使用方便,容错率高.
package cn.itcast.multiFactory;
import com.sun.org.apache.xpath.internal.operations.Mult;
import cn.itcast.staticfactory.BJBuns;
import cn.itcast.staticfactory.IBuns;
import cn.itcast.staticfactory.SCBuns;
import cn.itcast.staticfactory.TJBuns;
//多方法工厂
public class MultiFactory {
//模仿Executors类
//生产天津包子
public static IBuns createTJBBus(){
return new TJBuns();
}
//生产北京包子
public static IBuns createBJBBus(){
return new BJBuns();
}
//生产四川包子
public static IBuns createSCBuns(){
return new SCBuns();
}
//--------使用多方法静态工厂(模仿Executor类)----------
public static void main(String[] args) {
MultiFactory.createBJBBus().desc();
MultiFactory.createSCBuns().desc();
MultiFactory.createTJBBus().desc();
}
}
源码部分
java源码:java.util.concurrent.Executors类便是一个生成Executor的工厂,其采用的便是多方法的静态工厂模式.
ThreadPoolExecutor类构造方法有5个参数,其中三个参数写法固定,前两个参数可以配置.
生产者
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
JDK想增加创建ForkJoinPool类的方法,只想配置parallelism参数,便在类里面加一个下面的方法:
public static ExecutorService newWorkStealingPool(int parallelism) {
return new ForkJoinPool
(parallelism,
ForkJoinPool.defaultForkJoinWorkerThreadFactory,
null, true);
}
普通工厂
- 把简单工厂中具体的工厂类,划分成两层:抽象工厂层+具体的工厂子类层
- 1.抽象工厂类
package cn.itcast.factory;
import cn.itcast.staticfactory.IBuns;
//抽象工厂类:作用就是生产包子
public abstract class IBunsFactory {
public abstract IBuns create();
}
- 2.具体工厂子类(3个)
package cn.itcast.factory;
import cn.itcast.staticfactory.BJBuns;
import cn.itcast.staticfactory.IBuns;
//具体工厂子类:就是生产北京包子
public class BJFactory extends IBunsFactory{
public IBuns create(){
return new BJBuns();
}
}
package cn.itcast.factory;
import cn.itcast.staticfactory.IBuns;
import cn.itcast.staticfactory.SCBuns;
public class SCFactory extends IBunsFactory {
public IBuns create() {
return new SCBuns();
}
}
package cn.itcast.factory;
import cn.itcast.staticfactory.IBuns;
import cn.itcast.staticfactory.TJBuns;
public class TJFactory extends IBunsFactory {
public IBuns create() {
return new TJBuns();
}
}
- 3.使用
//拿第三个具体工厂来说,这样做就可以
public static void main(String[] args) {
IBunsFactory factory = new TJFactory();
factory.create().desc();
}
普通工厂与简单工厂模式的区别:
普通工厂模式特点:做出来的产品要抽象,工厂也要抽象
工厂方法使一个产品类的实例化延迟到其具体工厂子类.
工厂方法使一个产品类的实例化延迟到其具体工厂子类.
工厂方法的好处就是更拥抱变化.当需求变化,只需要增删相应的类,不需要修改已有的类.
而简单工厂需要修改工厂类的create()方法,多方法静态工厂模式需要增加一个静态方法,
- 缺点:
引入抽象工厂层后,每次新增一个具体产品类,也要同时新增一个具体工厂类,所以要用多方法静态工厂.
抽象工厂:多产品系列
就是说,每个Factory以前只生产包子,现在不行啦,我还要生产饮料.
- 1.先抽象一个产品类:
package cn.itcast.factory.product;
/**
* 厂家规定了你要卖多少钱
*/
public abstract class IDrinks {
public abstract void prices();
}
- 2.然后实现具体产品类
可乐:
package cn.itcast.factory.product;
public class ColaDrinks extends IDrinks {
@Override
public void prices() {
System.out.println("可乐3.5元!");
}
}
白开水:
package cn.itcast.factory.product;
public class WaterDrinks extends IDrinks {
@Override
public void prices() {
System.out.println("我现在是个穷逼,只能喝水.");
}
}
- 3.抽象工厂类
package cn.itcast.factory.product;
//抽象工厂类:1:生产包子,2:生产饮料
public abstract class AbstractFoodFactory {
//1.生产包子
public abstract IBuns createBuns();
//2.生产饮料
public abstract IBuns createDrinks();
}
- 4.具体工厂类(3个)
package cn.itcast.factory.product;
//具体工厂类:北京饭店厉害,卖包子和可乐,吃的带劲.
public class BJFoodFactory extends AbstractFoodFactory {
@Override
public IBuns createBuns() {
// TODO Auto-generated method stub
return new BJBuns();
}
@Override
public IDrinks createDrinks() {
// TODO Auto-generated method stub
return new ColaDrinks();
}
}
package cn.itcast.factory.product;
//天津包子好吃,一定要吃原味的.
public class TJFoodFactory extends AbstractFoodFactory{
public IBuns createBuns() {
return new TJBuns();
}
public IDrinks createDrinks() {
return new WaterDrinks();
}
}
package cn.itcast.factory.product;
//四川包子辣,当然要多喝水.
public class SCFoodFactory extends AbstractFoodFactory{
@Override
public IBuns createBuns() {
return new SCBuns();
}
@Override
public IDrinks createDrinks() {
return new WaterDrinks();
}
}
- 3.最终在抽象工厂里面调用就可以了
package cn.itcast.factory.product;
//抽象工厂类:1:生产包子,2:生产饮料
public abstract class AbstractFoodFactory {
//1.生产包子
public abstract IBuns createBuns();
//2.生产饮料
public abstract IDrinks createDrinks();
public static void main(String[] args) {
AbstractFoodFactory scFactory = new SCFoodFactory();
scFactory.createBuns().desc();
scFactory.createDrinks().prices();
System.out.println();
AbstractFoodFactory bjFactory = new BJFoodFactory();
bjFactory.createBuns().desc();
bjFactory.createDrinks().prices();
System.out.println();
AbstractFoodFactory tjFactory = new TJFoodFactory();
tjFactory.createBuns().desc();
tjFactory.createDrinks().prices();
}
}
- 输出结果
四川包子-味在辣椒!
我现在是个穷逼,只能喝水.
北京灌汤包-皮薄肉多!
可乐3.5元!
天津包子-狗不理,闻名天下!
我现在是个穷逼,只能喝水.
- 优点:
将工厂也抽象了,在使用时,工厂和产品都是面向接口的编程,OO(面向)不得了. - 缺点:
将工厂也抽象后,类爆炸了.
每次拓展新产品种类,比如,不进卖的吃喝,我还提供睡觉的服务,提供床位服务,这就要修改抽象工厂类了,
所以对于具体工厂子类,都被牵连,需要同步被修改.
七.总结
工厂模式:方便创建,同种产品类型的复杂参数,对象
工厂模式重点就是适用于构建通产品类型(同一接口 基类)的不同对象时,
这些对象new很复杂,需要很多的参数,而这些参数中大部分都是固定的,所以就可以封装它了.
为了适应程序的扩展性,拥抱变化.便衍生出了普通工厂,抽象工厂等模式.