Android框架设计模式(二)——(抽象)工厂模式

本文详细阐述了工厂模式在Android开发中的应用场景,包括简单工厂模式、工厂模式和抽象工厂模式,并通过Mp3播放器实例展示了如何在Android框架中应用工厂模式,以及如何通过Service角色作为抽象工厂来实现客户端与服务的解耦。此外,文章还总结了工厂模式的核心作用,以及在不同情况下的选择依据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、介绍


所有的工厂类都是一个目的:降低具体产品与调用者(比如说客户端)的耦合程度。对调用者隐藏产品的构造和变化(包括类名等)

举一个实际的例子,来证明工厂模式的应用场景。

public class Product {
    public void template(){//模板函数——不变
        //do something......
           hook_method();
    }
    public void hook_method();//卡榫函数——变
}
public class ProductA extends Product{
    public void hook_method(){
        //do something.....
    }
}
public class ProductB extends Product{
    public void hook_method(){
        //do something.....
    }
}
public class ProductC extends Product{
    public void hook_method(){
        //do something.....
    }
}
public class Client{
    public void main(String[] arg){
        Product proA = new ProductA();
        Product proB = new ProductB();
        Product proC = new ProductC();
        //.....如果说后面有一百个不同的Product,当然实际情况是,在不同的地方都会用到 new ProductA\B\C这样的具体字眼。
        proA.template();
        proB.template();
        proC.template();
    }
}

考虑下面的问题:

1、如果说这个时候,需求变了,要你把产品的名字改了,OMGD。可以想象,你需要改多少个 new ProductX(( ▼-▼ ))。

2、更加实际的情况是,有些产品是需要量产和包装的,它们的生产都是【标准化】的,因此如果构造这样的对象较多的话,客户端与具体的产品的耦合度就大大增加,同时,客户端承担的工作也过多。


使用工厂模式解决上面的困难

(1)简单工厂模式
  • UML结构

    这里写图片描述

  • 设计思想:简单工厂模式又叫静态工厂模式,在工厂模式系列中属于抽象层次最低的,也是最容易实现的。它是根据客户端的要求(传入的参数、调用的方法)来返回所需要的对象,能够很方便的实现客户端与具体产品之间的解耦。

  • 优缺点
    • 优点:结构简单,调用者只需要知道工厂和目标类别就可以。
    • 缺点:违反了开闭原则,如果添加产品类别的时候需要修改工厂代码。
  • 代码范例:
    模板模式+简单工厂
   public class Product {
    public void template(){//模板函数——不变
        //do something......
           hook_method();
    }
    public void hook_method();//卡榫函数——变
}
public class ProductA extends Product{
    public void hook_method(){
        //do something.....
    }
}
public class ProductB extends Product{
    public void hook_method(){
        //do something.....
    }
}
public class ProductC extends Product{
    public void hook_method(){
        //do something.....
    }
}
//简单工厂+模板模式
public class SimpleFactory{
   public static int TYPE_A = 1;//产品类别
   public static int TYPE_B = 2;
   public static int TYPE_C = 3;
   public Product pd; // 产品的引用
   public Product createProduct(int type){
       switch(type){
          case TYPE_A:
          pd = new ProductA();
          break;
          case TYPE_B:
          pd = new ProductB();
          break;
          case TYPE_C:
          pd = new ProductC();
          break;
       }
       pd.function();//调用模板初始化,包装对象,对象的具体包装留给具体类别去实现
       return pd;
   }
   public void function(){
       pd.template();  //模板模式,隐藏了具体实现,解除了工厂与对象具体包装的耦合
   }
}
public class Client{
    public void main(String[] arg){
      SimpleFactory fac = new SimpleFactory();
      Product proA = fac.createProduct(SimpleFactory.TYPE_A);
      Product proB = fac.createProduct(SimpleFactory.TYPE_B);
      Product proC = fac.createProduct(SimpleFactory.TYPE_C);
     //这个时候即使改变了产品的类名和实现,那么客户端也不需要知道,解除了客户端和具体产品的耦合
     //但是增加产品的时候,需要修改工厂类,违反了开闭原则,容易出错。
    }
} 

(2)工厂模式
  • UML结构:

    这里写图片描述

  • 设计思想:把对象的创建延迟到子类实现,不同子类负责实现不同对象的创建,父类工厂负责将对象返回给外部调用者。对外部隐藏了具体的类别;主要是针对类别单一的产品。

  • 优缺点:
    • 优点: 遵循开闭原则,如果添加产品类别则只需要添加继承类就可以,不需要修改工厂类的代码。
    • 缺点: 客户端需要知道具体的工厂名才能创建相应的对象;在某个产品有多个系列的时候,抽象工厂并不知道该创建哪个类别。
  • 代码范例:
   public class Product {
    public void template(){//模板函数——不变
        //do something......
           hook_method();
    }
    public void hook_method();//卡榫函数——变
}
public class ProductA extends Product{
    public void hook_method(){
        //do something.....
    }
}
public class ProductB extends Product{
    public void hook_method(){
        //do something.....
    }
}
public class ProductC extends Product{
    public void hook_method(){
        //do something.....
    }
}
//父类工厂
public class ProductFactory{
    public abstract Product createProduct();   
}
//具体子类工厂+模板模式
public class ProductAFactory{
    public Product createProduct(){
        Product pd = new ProductC();
        pd.template(); // 模板方法,初始化和装配对象
        return pd;
    }
}
public class ProductBFactory{
    public Product createProduct(){
        Product pd = new ProductC();
        pd.template(); // 模板方法,初始化和装配对象
        return pd;
    }
}
public class ProductCFactory{
    public Product createProduct(){
        Product pd = new ProductC();
        pd.template(); // 模板方法,初始化和装配对象
        return pd;
    }

}
public class Client{

      SimpleFactory facA = new ProductAFactory();
      SimpleFactory facB = new ProductBFactory();
      SimpleFactory facC = new ProductCFactory();

      //此处把具体产品的创建细节与客户端解耦
      Product proA = facA.createProduct(SimpleFactory.TYPE_A);
      Product proB = facB.createProduct(SimpleFactory.TYPE_B);
      Product proC = facC.createProduct(SimpleFactory.TYPE_C);
     //这个时候即使改变了产品的类名和实现,那么客户端也不需要知道,解除了客户端和具体产品的耦合
     //但是产品类别较多时,如果A、B、C下面各有两个风格时,那么工厂就不知道该创建哪一种了,这时候就需要用到抽象工厂模式了。
    }
} 
(3)抽象工厂模式
  • UML结构:

    这里写图片描述

  • 设计思想:工厂方法模式针对的是一个产品等级结构;而抽象工厂模式针对的是多个产品等级结构。当产品有多个等级结构或者多个系列的时候,就需要用到抽象工厂模式,使得客户端在不知道具体产品名的情况下创建具体的产品【不知而用】。

  • 优缺点:

    • 优点:在产品种类和系列比较多的情况下,行形成了一个产品等级结构时,可以将复杂的产品内部结构隐藏,简化客户端的操作。

    • 缺点: 当需要增加一个产品的时候,有多处需要添加新类;同时,如果对产品增加某个系列时需要修改原来的工厂类,违反开闭原则。

  • 代码范例:
    假设有C、D两个不同的产品,产品下面又分为两种不同风格,比 如:StyleC1、StyleC2、StyleD1、StyleD2。
    这时候结构就需要改变了,抽象工厂有两个模板方法(createC、createD),负责生产StyleC和StyleD,但是抽象工厂本身是不知道是哪个类型的风格。

    具体风格的创建延迟给两个子类工厂FactoryStyle1和FactoryStyle2负责。

//不同类别产品父类
public class ProductA extends Product{
    public void teplate(){ //模板函数——不变
        //do something.....
        hook_method();
    }
    public void hook_method();//卡榫函数——变化
}
public class ProductB extends Product{
    public void teplate(){ //模板函数——不变
        //do something.....
        hook_method();
    }
    public void hook_method();//卡榫函数——变化
}
//不同风格产品
public class ProductSytleA1 extends ProductA{
    public void hook_method(){
        //do something.....
    }
}
public class ProductStyleB1 extends ProductB{
    public void hook_method(){
        //do something.....
    }
}
public class ProductSytleA2 extends ProductA{
    public void hook_method(){
        //do something.....
    }
}
public class ProductStyleB2 extends ProductB{
    public void hook_method(){
        //do something.....
    }
}
//抽象父类工厂
public class ProductFactory{
    public abstract ProductA createA(); 
    public abstract ProductB createB(); 
    public abstract ProductC createC(); 
}
//具体子类工厂+模板模式
public class FactoryStyle1{
    public ProductA createA(){
        ProductA pd = new ProductStyleA1();
        pd.template(); // 模板方法,初始化和装配对象
        return pd;
    }
    public ProductB createB(){
        ProductB pd = new ProductStyleB1();
        pd.template(); // 模板方法,初始化和装配对象
        return pd;
    }
    public ProductC createC(){
        ProductC pd = new ProductStyleC1();
        pd.template(); // 模板方法,初始化和装配对象
        return pd;
    }
}
public class FactoryStyle2{
    public ProductA createA(){
        ProductA pd = new ProductStyleA2();
        pd.template(); // 模板方法,初始化和装配对象
        return pd;
    }
    public ProductB createB(){
        ProductB pd = new ProductStyleB2();
        pd.template(); // 模板方法,初始化和装配对象
        return pd;
    }
    public ProductC createC(){
        ProductC pd = new ProductStyleC2();
        pd.template(); // 模板方法,初始化和装配对象
        return pd;
    }
}

//客户端
public class Client{
    public void main(String[] arg){
      //生产Style1类型的产品
      Factory fac1 = new FactoryStyle1();
      ProductA proA = fac1.createA();//此时解除了具体产品与客户端的耦合。
      ProductB proB1 = fac1.createB();

      //生产Style2类型产品
      Factory fac2 = new FactoryStyle2();
      proA = fac2.createA();//客户端根本不知道此时风格已经变了。
      proB = fac2.createB();
      //如果需要更多的类型,则只需要知道工厂就可以了
      //如果需要改变产品的构造和名字,也无需通知客户端
      //抽象工厂模式类别层次结构复杂,所以适合在产品层次较深、类别较多的情况
    }
}

二、Android综合运用范例


还是之前的Mp3播放器,在Android之中客户端(Activity)与播放器(MP3Player)之间解耦就是用到了工厂模式。这时候Service就充当了Factory的角色。当然里面还有Template模式和Observer模式。

UML图示:

这里写图片描述

源代码

参见Android框架设计模式(一)——Template Method

分析

这里面,Service除了是单独运行在后台的独立线程之外,它还是充当了抽象工厂的角色,具体工厂是我们自己继承实现的mp3Service_Factory:

public class mp3Service_Factory extends Service {  
    private IBinder mBinder = null;  
    @Override public void onCreate() {
    //此处就生成了MP3Player对象
      mBinder = new mp3Player(getApplicationContext()); 
    }  
    //该函数就是Service与子类的卡榫函数
    @Override public IBinder onBind(Intent intent) {    
    return mBinder; //返回对象
    }
} 

结合UML图看,如果我们现在还有电影、下载的需求,那么我们又可以继承IBinder类来实现不同产品,继承Service实现不同的装配工厂。然而客户端呢,永远就只需要知道IBinder和具体工厂便足够。
分解一下具体的步骤:
1、我们可以看到,客户端调用startService()来启动服务,随后就启动了Service抽象类反向呼叫了mp3Service_Factory的onCreate()函数,诞生了mp3Player产品对象。然后执行bindService()函数,将mConnection这个回调类(CallBack)与Service绑定。

public void onCreate(Bundle icicle) {   super.onCreate(icicle);
//do initial
//开启服务
startService(new Intent(this, mp3Service_Factory.class));   
//将客户端与服务进行绑定,通过mConnection中的卡榫函数回调来返回Service工厂所创建的MP3Player对象。
bindService(new Intent(Client.this,mp3Service_Factory.class), mConnection, Context.BIND_AUTO_CREATE); 
 } 

2、创建了对象之后,Service抽象类反向呼叫了mp3Factory子类的onBind()卡榫函数返回了mp3Player对象。然后Service抽象类再用mConnection回调onServiceConnected()函数:

private ServiceConnection mConnection = new ServiceConnection() {       
   public void onServiceConnected(ComponentName className, IBinder ibinder)  {   
   ib = ibinder;   
   }         
   public void onServiceDisconnected(ComponentName className) {}      
   }; 

将 创建好的MP3Player对象返回给客户端的ib(只是抽象IBinder,并没有涉及具体类名)。
3、客户端获取到了mp3Player对象后,调用IBinder里面的transact()函数反向呼叫到mp3Player的onTransact()函数,从而实现音乐的播放。

//卡榫函数,接通mp3Player与父类IBinder
@Override
    protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
        if (1 == code){
            this.play();
        }else if ( 2 == code){
            this.stop();
        }
        return true;
    }

4、请留意,从始至终,客户端只知道IBinder对象而已,并不知道具体的mp3Player,也就是说如果这个时候mp3Player改变类名、构造等客户端都不知道的,即使换成mp4Player客户端也是不知道的,只需要实现一个mp4的工厂就可以了。


三、总结


其实上面的onServiceConnect()回调还是Observer模式,这个模式实现了客户端与后台服务的异步通信,可以让后台服务在准备好的时候通知客户端(在这里即返回mp3Player对象)。
总的来说,工厂模式是用来解决以下问题的:
(1) 对调用者隐藏具体的产品细节,调用者只需要告诉工厂需要生产什么样(磨具)的产品,而不需要知道具体产品的细节(类名)。

(2) 包装对象的构造过程,直接将产品返回给调用者,减轻调用者的负担。

(3) 至于用哪种工厂模式,就要依照具体项目的复杂程度了。简单的,不需要拓展的直接用简单工厂,单一的产品就用工厂模式,产品延伸链较长、类别较多则使用抽象工厂。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值