设计模式之工厂模式

工厂模式其实很简单,在这里就简单的说一下自己的心得体会,随时补充和修正自己对工厂模式的认知。

question one:工厂是干什么的?当然是生产东西的,在Java的世界或者面向对象编程的世界里,工厂是用来生产对象实例的

当然一个工厂生产的产品具有共性,比如一个工厂专门用来生产手机,不管是红色的手机、黄色的手机、拍照用的手机,老年人用的手机 等等其共性就是手机这个产品。所以可以抽象出Phone这个接口。如果一个工厂生产的东西不一样,也就是说没有共性,那么在面向对象的世界里工厂模式就没用武之地。在Java世界中具有共性的东西叫什么:Interface或者abstract class。许多implements 一个interface或者extends 一个抽象类的子类因为其接口或者父类而具有了共性。

interface Phone {
  void call();//具有共同的行为打电话
}

工厂模式的作用就是从这些共性的产品中,根据某种原则返回一个具体的产品对象出来。

所以简单工厂模式就出炉了:

public class PhoneFactory {
  //注意此处是static的
   public static Phone create(String pattern) {
      switch(pattern){
         case a:
            return new PhoneA();
        case b:
            return new PhoneB();    
      }
   }
}

这样我们客户端的代码就很简单了:

void call(String pattern) {
   Phone phone = PhoneFactory.create(pattern);
   phone.call();
}

客户端没必要知道手机对象创建的具体细节,只要根据匹配规则拿到手机后执行call这个行为就可以了。这也是工厂模式优点的体现:因为Phone接口指定了实现此接口类的行为call,那么子类只需要重写这个方法即可。如果没有工厂模式的话可能就会如下面这个代码了:

void call(String pattern) {
   Phone phone;
   switch(pattern){
         case a:
           phone= new PhoneA();
        case b:
           phone=new PhoneB();    
      }
      if(phone!=null)
         phone.call();
}

这段代码不仅对客户端暴露太多的对象创建细节,而且如果有多个页面或者模块需要打电话的话,可能会ctrl+c/v大法,然后需要改动的时候各个模块都需要改动;可能好一点设计的就是抽象一个公共utils方法了。

其实工厂模式之所以能成功,是面向抽象/接口编程的合理应用的必然结果,Phone接口使得其子类具有共同的call行为(算是接口的约束作用)。所以使用客户端工厂模式(如上)代码可以很简洁。如果没有接口约束作用也就是说每个电话对象不实现Phone接口,且每个电话对象打电话的方法都不一样,比如PhoneA的打电话为call(),PhoneB()打电话的方法叫hello()等等吧,上面的call方法就可能更复杂:

void call(String pattern) {
   switch(pattern){
         case a:
           PhoneA phoneA= new PhoneA();
           phoneA.call();
           break;
        case b:
           PhoneB phoneB= new PhoneB();
           phoneB.hello();
           break;
      }
  
}

随着更多不同电话的加入,每个电话都有不同拨打电话的入口方式;你不得不阅读说明书(api)来知道每部电话该拨打电话,想想就头大。

而定义一个Phone接口,打电话的行为就是call(),那么你从工厂里拿道手机直接call就行了。 面向接口或者面向抽象编程的有点体现淋漓尽致。可以说如果没有了接口或者抽象类,就不会存在设计模式这套东西,所以掌握类的设计原则:面向抽象或者接口编程,其实还是很有必要的,接口和抽象的作用是便于扩展, 核心就是告诉你在写代码的时候 注意开闭原则。

其实仔细想想,与其说工厂模式是个模式,不如说是一个代码编写习惯,把创建对象的具体职责统一起来即可。

工厂模式虽然很简单,但是应用确很广泛,比如大名鼎鼎的Retrofit,Okhttp等等框架都有这该模式的影子。

刚才博主一直强调 面向抽象和接口编程,那么能不能对工厂进行抽象呢?当然能,这就是抽象工厂模式了。下一篇会详细介绍

简单的来个实战例子:
先来看下面这个效果图:


在这里插入图片描述

如图,上面一个RecycleView的列表,每一个Item都有一个点击按钮;不同的点击跳转或者执行不同的逻辑;如果是常规写法的话可能就是如下代码:

ItemData itemData  = list.get(position)
 holder.btn.setOnClickListener(new View.OnClickListener() {
         @Override
            public void onClick(View v) {
                   if(itemId==0){
                       doA(context,itemData);
                    }else if(itemId == 1){
                     doB(context,ItemData)
                     } else if(....){
                    }else{
                   }
            }
 }

public void doA(Context context,ItemData data){
  Log.i("执行A相关的逻辑")
}

如果item多的话,上面的if-else会急剧膨胀,后期的扩展和维护都不强;如果用上工厂模式的话简单多了。对这个页面进行需求分析, 点击一个item的时候跳转到其他页面,然后可能携带 一些item本身的数据;所以对这个行为抽象成一个接口:

public interface IItemClick {
  //点击某item按钮执行的动作
    void doClick(Context context, ItemData data);
}

然后在RecycleView的onClick方法里就可以这么写:

  holder.btn.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                   
                    IItemClick itemClick = ItemClickFactory.create(itemData.getId());
                    itemClick .doClick(v.getContext(), itemData);
                }
            });

这段代码就是讲if-else if--else代码块中的逻辑抽象成出IItemClick 接口,然后将具体的逻辑交给doClick方法即可。比如上述doA方法,交给AClick :

class AClick implements IItemClick{
   public void doClick(Context context,ItemData data){
        Log.i("执行A相关的逻辑")
   }
}

这样不管有多少个item,holder.btn.setOnClickListener的代码都不需要变动;你只需要提供一个实现了IItemClick接口的类,然后在 ItemClickFactory.create中返回即可。

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

推荐阅读更多精彩内容

  • 夜莺2517阅读 127,720评论 1 9
  • 版本:ios 1.2.1 亮点: 1.app角标可以实时更新天气温度或选择空气质量,建议处女座就不要选了,不然老想...
    我就是沉沉阅读 6,898评论 1 6
  • 我是黑夜里大雨纷飞的人啊 1 “又到一年六月,有人笑有人哭,有人欢乐有人忧愁,有人惊喜有人失落,有的觉得收获满满有...
    陌忘宇阅读 8,537评论 28 53
  • 兔子虽然是枚小硕 但学校的硕士四人寝不够 就被分到了博士楼里 两人一间 在学校的最西边 靠山 兔子的室友身体不好 ...
    待业的兔子阅读 2,604评论 2 9