第二章——工厂方法模式

又是新的一天,今天是19大闭幕式,呵呵我的股票长了点,唉总算是收回了点成本,我是实践中深刻体会到了这句话的内涵,股市有风险,入市需谨慎;还是少玩的好;今天我们来玩玩工厂方法模式.
先看下定义:
工厂方法模式定义:Define an interface for creating an object,but let subclasses decide which class to
instantiate.Factory Method lets a class defer instantiation to subclasses.(定义一个用于创建对象的
接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。),

工厂方法模式是一个应用最广泛的设计模式,也是一个高度解耦的设计模式:咱们今天从代码中展开,相信任何一个有经验的程序员一看就了然。
今天同事准备买电脑让我帮他推荐个电脑,咱们就以电脑为例吧:

  public interface Computer {
/**
 * 电脑型号
 * 
 * @return
 */
public String getModelNumber();

/**
 * 电脑出厂价
 * 
 * @return
 */
public String getComputerPrice();

/**
 * 电脑的基本配置
 * 
 * @return
 */
public String getComputerDesc();
     }


 public class InspirationComputer implements Computer {
@Override
public String getModelNumber() {
    return "灵越系列Ins15E-3725";
}

@Override
public String getComputerPrice() {
    
    return "3333元";
}

@Override
public String getComputerDesc() {

    return "适用场景 家庭影音 女性定位 轻薄便携 学生 商务办公 高清游戏 家庭娱乐";
}
   }
     public class VostroComputer implements Computer {

@Override
public String getModelNumber() {
    // TODO Auto-generated method stub
    return "Vostro 5459-1528";
}

@Override
public String getComputerPrice() {
    // TODO Auto-generated method stub
    return "¥ 4499.00";
}

@Override
public String getComputerDesc() {
    // TODO Auto-generated method stub
    return "适用场景     商务办公 家庭娱乐";
}}

戴尔工厂里生产电脑;那么电脑有型号有价格,和基本配置定位;这是产品的共有特性;我们用一个接口来统一定义这些方法;注意面向接口编程一个好处就是便于扩展;有了电脑就应该有工厂去生产:

            /**
              *  抽象工厂上层
             *
             */      
     public abstract class AbsrtactComputerFactory {
// 限制传入类型只能是Computer的子类
   public abstract <T extends Computer> T createComputer(Class<T> c);
       }

    /**
    * 具体的工厂方法实现,目的就是生产电脑
   * 
    * @author Administrator
  *
  */

  public class ComputerFactory extends AbsrtactComputerFactory {
@Override
public <T extends Computer> T createComputer(Class<T> c) {
    Computer computer = null;
    try {
        computer = (T) Class.forName(c.getName()).newInstance();
    } catch (Exception e) {

        e.printStackTrace();
    }

    return (T) computer;
}}

好了现在我们有了工厂了,可以开工了:

    public static void main(String[] args) {
    // TODO Auto-generated method stub
    AbsrtactComputerFactory compFactory = new ComputerFactory();
    Computer inspirationComputer = compFactory.createComputer(InspirationComputer.class);
    System.out.println(inspirationComputer.getComputerDesc() + "\n" + inspirationComputer.getModelNumber() + "\n"
            + inspirationComputer.getComputerPrice());
    Computer vostroComputer = compFactory.createComputer(VostroComputer.class);
    System.out.println(vostroComputer.getComputerDesc() + "\n" + vostroComputer.getModelNumber() + "\n"
            + vostroComputer.getComputerPrice());
}
图片.png

由图可见,我们构造了一个工厂生产了两台不同型号的电脑,简单吧,这就是工厂方法模式的通用用法。

列举下他的优点吧:
1.良好的封装性,代码结构清晰;
一个对象创建是有条件约束的,如一个调用者需要一个具体的产品对象,只要知道这个产品的类名(或约束字符串)就可以了,不用知道创建对象的艰辛过程,降低模块间的耦合;对于调用者来说我们只需要知道生产什么型号的电脑,知道类名就可以,不需要关注这个类怎么创建的.
2.扩展性非常优秀;
就代码而言,如果我们需要生产一个X型号的电脑,具有特殊特性不具备公共特性怎么办?我们只需要增加一个X型即可,并且再此进行特性扩展,不需要修改工厂生产的上层封装;
如果盘子大了怎么办?遇到业务代码很多,我们是不是可以考虑开辟不同的工厂专司其职呢,比如我们想戴尔灵越系列专职由一个工厂生产,Vostro系列专由一个工厂生产,结构更清晰,我们完全可以创建不同的工厂去做,这也是面向接口编程的好处,但是也有弊端,因为维护成本就高了,产品和工厂是一一对应的关系,有几个产品就要创建几个工厂.

3.屏蔽产品类
产品类的实现如何变化,调用者都不需要关心,它只需要关心产品的接口,只要接口保持不变,系统中的上层模块就不会发生变化,也就是从上到下的过程,

以上是工厂方法模式的标准写法,下面我们看看工厂方法模式的几个变种使用:

1.简单工厂模式:
每次都要创建一个工厂太费劲了,我们把工厂的抽象去掉,创建的方法改成静态:

   public class ComputerFactory  {
   public static <T extends Computer> T createComputer(Class<T> c) {
    Computer computer = null;
    try {
        computer = (T) Class.forName(c.getName()).newInstance();
    } catch (Exception e) {

        e.printStackTrace();
    }

    return (T) computer;
}
 }
        



     public static void main(String[] args) {
    // TODO Auto-generated method stub
    Computer comp=ComputerFactory.createComputer(InspirationComputer.class);
      //        AbsrtactComputerFactory compFactory = new ComputerFactory();
 //     Computer inspirationComputer = compFactory.createComputer(InspirationComputer.class);
//      System.out.println(inspirationComputer.getComputerDesc() + "\n" + inspirationComputer.getModelNumber() +           "\n"
                //              + inspirationComputer.getComputerPrice());
            //      Computer vostroComputer = compFactory.createComputer(VostroComputer.class);
         //     System.out.println(vostroComputer.getComputerDesc() + "\n" + vostroComputer.getModelNumber() + "\n"
       //               + vostroComputer.getComputerPrice());
    System.out.println(comp.getComputerDesc() + "\n" + comp.getModelNumber() + "\n"
            + comp.getComputerPrice());
} 

现在是不是清爽了许多,这种方式应用还是很广泛的,叫做简单工厂模式,但是工厂类的扩展就不那么方便了

2.多工厂模式:我们还是看代码

   public abstract class AbsrtactComputerFactoryzz {
public abstract Computer createComputer();}
  


    public class InspirationFactory extends AbsrtactComputerFactoryzz {

@Override
public Computer createComputer() {
    return new InspirationComputer();
}}

我们创建了抽象工厂类,工厂里的方法还是生产电脑,这一点不容置疑,就像多年前一个前辈说的,人在黑板上花圆,现在有人,黑板,圆三个对象,画圆的方法应该谁提供呢?很明显是圆,圆包含半径,圆心,自然是它;
由于是多工厂模式,自然各个工厂各司其职,在子类中写死这个工厂干什么的就行了;

3.替代单例模式

故名思议,这是一种可以用工厂方式做到单例设计模式的一种工厂变体,其实这是不明智的,开发有开发的规矩,不能使用一些非正常手段去实现通常写法,但是也要了解一下,我们看下代码:

   public class CommonFactoryTest {
private static CommonFactoryTest singleton;
static {
    try {
        Class cl = Class.forName(CommonFactoryTest.class.getName());
        // 获得无参构造
        Constructor constructor = cl.getDeclaredConstructor();
        // 设置无参构造是可访问的
        constructor.setAccessible(true);
        // 产生一个实例对象
        singleton = (CommonFactoryTest) constructor.newInstance();
    } catch (Exception e) {
        // 异常处理
    }
}

public static CommonFactoryTest getSingleton() {
    return singleton;
}}

我们用暴力反射技术,和classload的机制保证内存中只有一个实例存在,但是很明显效率是相当低的,不应该这么干。

4.延迟初始化,

一个对象被消费完毕后,并不立刻释放,工厂类保持其初始状态,等待再次被使用;
比如说我们不希望一个对象频繁销毁,想复用时候,比如做内存缓存的时候,但是应当注意内存泄漏的可能;比如Android开发中首页tab的fragment我们就可以用这种方式保存其产品的状态不被释放以利复用;下面看一下代码:

         public static final int PLAYSHARE_SFRAGMENT = 0;
public static final int DISCUSS_FRAGMENT = 1;
public static final int MARKET_FRAGMENT = 2;
public static final int CONSULTING = 3;
public static final int MY_FRAGMENT = 4;
private static SparseArray<BaseFragment> mFragments = new SparseArray<BaseFragment>();
public static BaseFragment createFragment(int position) {
    BaseFragment fragment = mFragments.get(position);
    if (fragment == null) {
        switch (position) {
            case PLAYSHARE_SFRAGMENT:
                fragment = new PlaySharesFragment();
                break;
            case DISCUSS_FRAGMENT:
                fragment = new DiscussFragment();
                break;
            case MARKET_FRAGMENT:
                fragment = new QuotationFragment();
                break;
            case CONSULTING:
                fragment = new ConsultingFragment();
                break;
            case MY_FRAGMENT:
                fragment = new MyFragment();
                break;
            default:
                break;
        }
        mFragments.put(position, fragment);
    }
    return fragment;
}

很明显,代码对我们需要的产品进行了缓存再利用;无论你用Map容器也好还是其他List集合也好,原理都一样都是希望对已有产品的再利用,这个方式应用也很广泛,但是应当注意缓存的释放;

工厂方法模式总结:
是典型的解耦框架,高层模块只需要知道产品的抽象类,其他的实
现类都不用关心,符合迪米特法则,我不需要的就不要去交流;也符合依赖倒置原则,只依
赖产品类的抽象;当然也符合里氏替换原则,使用产品子类替换产品父类

使用场景:
万物皆对象,工厂方法模式是用来生产对象,他可以替代new Object ,任何使用 new 对象的地方我们都可以用工厂模式替代,但是我们要考虑是否值得这么做,因为这样对于开发者不也是增加了代码复杂度吗?
Ok今天就先到这里了,

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

推荐阅读更多精彩内容

  • 设计模式汇总 一、基础知识 1. 设计模式概述 定义:设计模式(Design Pattern)是一套被反复使用、多...
    MinoyJet阅读 3,897评论 1 15
  • 1 场景问题# 1.1 导出数据的应用框架## 考虑这样一个实际应用:实现一个导出数据的应用框架,来让客户选择数据...
    七寸知架构阅读 6,481评论 6 72
  • 1 场景问题# 1.1 选择组装电脑的配件## 举个生活中常见的例子——组装电脑,我们在组装电脑的时候,通常需要选...
    七寸知架构阅读 4,271评论 6 66
  • 影片《重返二十岁》中,已经迟暮的老太太沈梦君因为想留住最后的青春,去了一家照相馆,结果变回二十岁时的容貌了,又惊又...
    王玬锦阅读 508评论 0 1
  • 今天休假,又是闲的发愁的一天。抱着手机看了几集《我的前半生》,中午看着看着手机给睡着了,唉,现在可以说我的半条命都...
    liuliuliu2016阅读 310评论 0 0