02-工厂模式

包含的对象

属于创建型设计模式,需要生成的对象叫做产品 ,生成对象的地方叫做工厂

使用场景

在任何需要生成复杂对象的地方,都可以使用工厂方法模式。
直接用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很复杂,需要很多的参数,而这些参数中大部分都是固定的,所以就可以封装它了.
为了适应程序的扩展性,拥抱变化.便衍生出了普通工厂,抽象工厂等模式.

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,717评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,501评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,311评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,417评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,500评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,538评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,557评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,310评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,759评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,065评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,233评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,909评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,548评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,172评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,420评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,103评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,098评论 2 352

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,608评论 18 399
  • 设计模式汇总 一、基础知识 1. 设计模式概述 定义:设计模式(Design Pattern)是一套被反复使用、多...
    MinoyJet阅读 3,934评论 1 15
  • 设计模式基本原则 开放-封闭原则(OCP),是说软件实体(类、模块、函数等等)应该可以拓展,但是不可修改。开-闭原...
    西山薄凉阅读 3,784评论 3 14
  • 目前,java版支付中心处在研发阶段。下午,特有钻研精神的云龙同学饶有兴趣的问我“战哥,你觉得表字段用哪种命名方式...
    buguge阅读 2,454评论 0 12
  • 01 那日,我照旧在闺房梳妆理鬓,余光瞥见镜中映出异样的光,还来不及细想,已有人影打破了这静谧。 如风,似雨,大约...
    驿路奇奇阅读 682评论 37 40