设计模式之工厂模式

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

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中返回即可。

你可能感兴趣的:(设计模式之工厂模式)