A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

1黑马币
在面试的时候,越来越多的学员被问到一些高级的设计思想,如设计模式,今天给大家分享一个设计模式,绝大多数的android框架都是基于抽象工厂设计模式来设计的。
一、介绍
所有的工厂类都是一个目的:降低具体产品与调用者(比如说客户端)的耦合程度。对调用者隐藏产品的构造和变化(包括类名等)
举一个实际的例子,来证明工厂模式的应用场景。
  1. public class Product {
  2.         public void template() {// 模板函数——不变
  3.                 // do something......
  4.                 hook_method();
  5.         }

  6.         public void hook_method();// 卡榫函数——变
  7. }

  8. public class ProductA extends Product {
  9.         public void hook_method() {
  10.                 // do something.....
  11.         }
  12. }

  13. public class ProductB extends Product {
  14.         public void hook_method() {
  15.                 // do something.....
  16.         }
  17. }

  18. public class ProductC extends Product {
  19.         public void hook_method() {
  20.                 // do something.....
  21.         }
  22. }

  23. public class Client {
  24.         public void main(String[] arg) {
  25.                 Product proA = new ProductA();
  26.                 Product proB = new ProductB();
  27.                 Product proC = new ProductC();
  28.                 // .....如果说后面有一百个不同的Product,当然实际情况是,在不同的地方都会用到 new ProductA\B\C这样的具体字眼。
  29.                 proA.template();
  30.                 proB.template();
  31.                 proC.template();
  32.         }
  33. }
复制代码

考虑下面的问题:
1、如果说这个时候,需求变了,要你把产品的名字改了,OMGD。可以想象,你需要改多少个 new ProductX(( ▼-▼ ))。
2、更加实际的情况是,有些产品是需要量产和包装的,它们的生产都是【标准化】的,因此如果构造这样的对象较多的话,客户端与具体的产品的耦合度就大大增加,同时,客户端承担的工作也过多。
使用工厂模式解决上面的困难(1)简单工厂模式
  • UML结构

  • 设计思想:简单工厂模式又叫静态工厂模式,在工厂模式系列中属于抽象层次最低的,也是最容易实现的。它是根据客户端的要求(传入的参数、调用的方法)来返回所需要的对象,能够很方便的实现客户端与具体产品之间的解耦。
  • 优缺点
    • 优点:结构简单,调用者只需要知道工厂和目标类别就可以。
    • 缺点:违反了开闭原则,如果添加产品类别的时候需要修改工厂代码。
  • 代码范例:
    模板模式+简单工厂
    1. public class Product {
    2.     public void template(){//模板函数——不变
    3.         //do something......
    4.            hook_method();
    5.     }
    6.     public void hook_method();//卡榫函数——变
    7. }
    8. public class ProductA extends Product{
    9.     public void hook_method(){
    10.         //do something.....
    11.     }
    12. }
    13. public class ProductB extends Product{
    14.     public void hook_method(){
    15.         //do something.....
    16.     }
    17. }
    18. public class ProductC extends Product{
    19.     public void hook_method(){
    20.         //do something.....
    21.     }
    22. }
    23. //简单工厂+模板模式
    24. public class SimpleFactory{
    25.    public static int TYPE_A = 1;//产品类别
    26.    public static int TYPE_B = 2;
    27.    public static int TYPE_C = 3;
    28.    public Product pd; // 产品的引用
    29.    public Product createProduct(int type){
    30.        switch(type){
    31.           case TYPE_A:
    32.           pd = new ProductA();
    33.           break;
    34.           case TYPE_B:
    35.           pd = new ProductB();
    36.           break;
    37.           case TYPE_C:
    38.           pd = new ProductC();
    39.           break;
    40.        }
    41.        pd.function();//调用模板初始化,包装对象,对象的具体包装留给具体类别去实现
    42.        return pd;
    43.    }
    44.    public void function(){
    45.        pd.template();  //模板模式,隐藏了具体实现,解除了工厂与对象具体包装的耦合
    46.    }
    47. }
    48. public class Client{
    49.     public void main(String[] arg){
    50.       SimpleFactory fac = new SimpleFactory();
    51.       Product proA = fac.createProduct(SimpleFactory.TYPE_A);
    52.       Product proB = fac.createProduct(SimpleFactory.TYPE_B);
    53.       Product proC = fac.createProduct(SimpleFactory.TYPE_C);
    54.      //这个时候即使改变了产品的类名和实现,那么客户端也不需要知道,解除了客户端和具体产品的耦合
    55.      //但是增加产品的时候,需要修改工厂类,违反了开闭原则,容易出错。
    56.     }
    57. }
    复制代码
    (2)工厂模式
    • UML结构:

    • 设计思想:把对象的创建延迟到子类实现,不同子类负责实现不同对象的创建,父类工厂负责将对象返回给外部调用者。对外部隐藏了具体的类别;主要是针对类别单一的产品。
    • 优缺点:
      • 优点: 遵循开闭原则,如果添加产品类别则只需要添加继承类就可以,不需要修改工厂类的代码。
      • 缺点: 客户端需要知道具体的工厂名才能创建相应的对象;在抽象产品有多个类别的时候,工厂并不知道该创建哪个类别。
    • 代码范例:
      1. public class Product {
      2.     public void template(){//模板函数——不变
      3.         //do something......
      4.            hook_method();
      5.     }
      6.     public void hook_method();//卡榫函数——变
      7. }
      8. public class ProductA extends Product{
      9.     public void hook_method(){
      10.         //do something.....
      11.     }
      12. }
      13. public class ProductB extends Product{
      14.     public void hook_method(){
      15.         //do something.....
      16.     }
      17. }
      18. public class ProductC extends Product{
      19.     public void hook_method(){
      20.         //do something.....
      21.     }
      22. }
      23. //父类工厂
      24. public class ProductFactory{
      25.     public abstract Product createProduct();   
      26. }
      27. //具体子类工厂+模板模式
      28. public class ProductAFactory{
      29.     public Product createProduct(){
      30.         Product pd = new ProductC();
      31.         pd.template(); // 模板方法,初始化和装配对象
      32.         return pd;
      33.     }
      34. }
      35. public class ProductBFactory{
      36.     public Product createProduct(){
      37.         Product pd = new ProductC();
      38.         pd.template(); // 模板方法,初始化和装配对象
      39.         return pd;
      40.     }
      41. }
      42. public class ProductCFactory{
      43.     public Product createProduct(){
      44.         Product pd = new ProductC();
      45.         pd.template(); // 模板方法,初始化和装配对象
      46.         return pd;
      47.     }

      48. }
      49. public class Client{
      50.     public void main(String[] arg){
      51.       SimpleFactory fac = new SimpleFactory();
      52.       Product proA = fac.createProduct(SimpleFactory.TYPE_A);
      53.       Product proB = fac.createProduct(SimpleFactory.TYPE_B);
      54.       Product proC = fac.createProduct(SimpleFactory.TYPE_C);
      55.      //这个时候即使改变了产品的类名和实现,那么客户端也不需要知道,解除了客户端和具体产品的耦合
      56.      //但是产品类别较多时,如果A、B、C下面各有两个风格时,那么工厂就不知道该创建哪一种了,这时候就需要用到抽象工厂模式了。
      57.     }
      58. }
      复制代码

      (3)抽象工厂模式
      • UML结构:

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

        • 优点:在产品类别比较多的情况下,
        • 缺点:  当需要增加一个产品类别的时候,需要增加的类比较多,结构比较复杂。
      • 代码范例:
          假设有C、D两个不同的产品,产品下面又分为两种不同风格,比如:StyleC1、StyleC2。
          这时候结构就需要改变了,抽象工厂就只有两个模板方法
        1. createC
              2. createD
        子类就有两个工厂分别为FactoryStyle1和FactoryStyle2
        具体创建Style1还是Style2就由具体的工厂来决定。
        1. public class ProductA extends Product{
        2.     public void teplate(){ //模板函数——不变
        3.         //do something.....
        4.         hook_method();
        5.     }
        6.     public void hook_method();//卡榫函数——变化
        7. }
        8. public class ProductB extends Product{
        9.     public void teplate(){ //模板函数——不变
        10.         //do something.....
        11.         hook_method();
        12.     }
        13.     public void hook_method();//卡榫函数——变化
        14. }
        15. //不同风格产品
        16. public class ProductSytleA1 extends ProductA{
        17.     public void hook_method(){
        18.         //do something.....
        19.     }
        20. }
        21. public class ProductStyleB1 extends ProductB{
        22.     public void hook_method(){
        23.         //do something.....
        24.     }
        25. }
        26. public class ProductSytleA2 extends ProductA{
        27.     public void hook_method(){
        28.         //do something.....
        29.     }
        30. }
        31. public class ProductStyleB2 extends ProductB{
        32.     public void hook_method(){
        33.         //do something.....
        34.     }
        35. }
        36. //抽象父类工厂
        37. public class ProductFactory{
        38.     public abstract ProductA createA();
        39.     public abstract ProductB createB();
        40.     public abstract ProductC createC();
        41. }
        42. //具体子类工厂+模板模式
        43. public class FactoryStyle1{
        44.     public ProductA createA(){
        45.         ProductA pd = new ProductStyleA1();
        46.         pd.template(); // 模板方法,初始化和装配对象
        47.         return pd;
        48.     }
        49.     public ProductB createB(){
        50.         ProductB pd = new ProductStyleB1();
        51.         pd.template(); // 模板方法,初始化和装配对象
        52.         return pd;
        53.     }
        54.     public ProductC createC(){
        55.         ProductC pd = new ProductStyleC1();
        56.         pd.template(); // 模板方法,初始化和装配对象
        57.         return pd;
        58.     }
        59. }
        60. public class FactoryStyle2{
        61.     public ProductA createA(){
        62.         ProductA pd = new ProductStyleA2();
        63.         pd.template(); // 模板方法,初始化和装配对象
        64.         return pd;
        65.     }
        66.     public ProductB createB(){
        67.         ProductB pd = new ProductStyleB2();
        68.         pd.template(); // 模板方法,初始化和装配对象
        69.         return pd;
        70.     }
        71.     public ProductC createC(){
        72.         ProductC pd = new ProductStyleC2();
        73.         pd.template(); // 模板方法,初始化和装配对象
        74.         return pd;
        75.     }
        76. }

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

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

        二、Android综合运用范例
        还是之前的Mp3播放器,在Android之中客户端(Activity)与播放器(MP3Player)之间解耦就是用到了工厂模式。这时候Service就充当了Factory的角色。当然里面还有Template模式和Observer模式。
        UML图示:
      • 三、总结
        其实上面的onServiceConnect()回调还是Observer模式,这个模式实现了客户端与后台服务的异步通信,可以让后台服务在准备好的时候通知客户端(在这里即返回mp3Player对象)。
        总的来说,工厂模式是用来解决以下问题的:
        1. 对调用者隐藏具体的产品细节,调用者只需要告诉工厂需要生产什么样(磨具)的产品,而不需要知道具体产品的细节(类名)。
        2.  包装对象的构造过程,直接将产品返回给调用者,减轻调用者的负担。
        3. 至于用哪种工厂模式,就要依照具体项目的复杂程度了。简单的,不需要拓展的直接用简单工厂,单一的产品就用工厂模式,产品延伸链较长、类别较多则使用抽象工厂。



2 个回复

倒序浏览
折磨牛啊  看不懂
回复 使用道具 举报
谢谢分享哦。。
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马