设计模式之工厂模式

工厂模式(Factory Method)是将客户类和工厂类分开。消费者任何时候需要某种产品,只需向工厂请求即可。消费者无须修改就可以接纳新产品。

工厂模式适用情况:当多个子类(产品)共同继承同一父类(工厂),并由消费者的要求指定生产某一种产品时使用该种设计模式。

工厂模式分为:

  • 简单工厂模式(Simple Factory)  

  • 工厂方法模式(Factory Method)  

  • 抽象工厂模式(Abstract Factory)   

简单工厂模式(Simple Factory)  

场景:当我到麦当当吃麦辣鸡腿汉堡,你可以对服务员说:“要一个麦辣鸡翅汉堡”,服务员就会给你提供该汉堡。

分析角色:

工厂类角色(Factory):这是本模式的核心,含有一定的商业逻辑和判断逻辑。在java中它往往由一个具体类实现。 场景中的麦当当的汉堡生产线就是工厂。

抽象产品角色(Abstract Product):它一般是具体产品继承的父类或者实现的接口。在java中由接口或者抽象类来实现。 场景中的汉堡就是抽象产品角色。

具体产品角色(Product):工厂类所创建的对象就是此角色的实例。在java中由一个具体类实现。 场景中的麦辣鸡翅汉堡就是具体产品角色。

//抽象产品角色

public interface Produce {    

      void doProduce();

}

//产品实例 1

public class SpicyChickenHamburg implements Produce{

   public void doProduce()   {

        System.out.println(“offer SpicyChickenHamburg ”);

   }

}

//产品实例 2 鸡腿堡

public class ChickenDrumsticksHamburg implements Produce{

   public void doProduce()   {

        System.out.println(“do ChickenDrumsticksHamburg ”);

   }

}

//工厂

public class MacDonaldHamburgFactory{

    public Produce getProduct(String productName) {

       if(“SpicyChickenHamburg”.equals(productName)){

           return new SpicyChickenHamburg();

       }else if(“ChickenDrumsticksHamburg”.equals(productName)){

           return new ChickenDrumsticksHamburg ();

       }else{

           return null;

       }

    }

}

简单工厂的好处与不足:

客户端免除了直接创建产品对象的责任,而仅仅负责“消费”产品。

下面我们从开闭原则上来分析下简单工厂模式。当产品新增时,只要符合抽象产品制定,那么只要通知工厂类知道就可以提供给消费者了。那么对于产品部分来说,它是符合开闭原则的--对扩展开放、对修改关闭。

但是工厂部分每增加一样商品,就需要修改相应的商业逻辑和判断逻辑,这显然是违背开闭原则的。

在实际应用中,很可能产品是一个多层次的树状结构。由于简单工厂模式中只有一个工厂类来对应这些产品,所以对于复杂的业务环境可能不太适应。

由此引出工厂方法模式。

工厂方法模式(Factory Method)  

场景:当我到麦当当,由于麦当当有很多的种类的产品,当我想吃吃麦辣鸡腿汉堡时,我对服务员说:“要一个麦辣鸡翅汉堡”,同时我在想来杯大可乐,服务员会对应给我相应的汉堡和可乐。

角色分析:

抽象工厂角色:这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。在java中它由抽象类或者接口来实现。 场景中麦当当提供产品就是抽象工厂。

具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。在java中它由具体的类来实现。场景中汉堡和可乐是两种不同的产品,但都具有提供产品的功能,因此他们都继承与麦当当这个抽象的工厂,分别为具体工厂角色。

抽象产品角色:它是具体产品继承的父类或者是实现的接口。在java中一般有抽象类或者接口来实现。 场景中汉堡和可乐都是抽象产品。

具体产品角色:具体工厂角色所创建的对象就是此角色的实例。在java中由具体的类来实现。场景中麦辣鸡翅汉堡和大可乐分别继承抽象产品中的汉堡和可乐,为具体产品角色。

//抽象产品角色

public interface Produce{    

      void doProduce();

}

//产品实例 1-1 麦辣鸡翅汉堡

public class SpicyChickenHamburg implements Produce{

   public void doProduce() {

        System.out.println(“offer SpicyChickenHamburg ”);

   }

}

//产品实例 1-2 鸡腿堡

public class ChickenDrumsticksHamburg implements Produce{

   public void doProduce()   {

        System.out.println(“do ChickenDrumsticksHamburg ”);

   }

}

//产品实例 2-1 小杯可乐

public class SmallCola    implements Produce{

   public void doProduce()   {

        System.out.println(“do SmallCola ”);

   }

}

//产品实例 2-2 大杯可乐

public class BigCola implements Produce{

   public void doProduce()   {

        System.out.println(“do BigCola ”);

   }

}

//抽象工厂角色

public interface MacDonaldFactory{    

  Produce getProduct(String productName);

}

//汉堡包工厂

public class MacDonaldHamburgFactory implements MacDonaldFactory{

    public Produce getProduct( String productName) {

      if(“SpicyChickenHamburg”.equals(productName)){

           return new SpicyChickenHamburg();

      } else if(“ChickenDrumsticksHamburg”.equals(productName)){

           return new ChickenDrumsticksHamburg();

      } else{

           return null;

      }

  }

}

public class MacDonaldColaFactory implements MacDonaldFactory{

    public Produce getProduct(String productName) {

    if(“big”.equals(productName)){

           return new BigCola ();

    }else if(“small”.equals(productName)){

           return new SmallCola ();

    }else {

           return null;

    }

  }

}

工厂方法使用一个抽象工厂角色作为核心来代替在简单工厂模式中使用具体类作为核心。

优点:

使用开闭原则来分析下工厂方法模式。当有新的产品产生时,只要按照抽象产品角色、抽象工厂角色提供的合同来生成,那么就可以被客户使用,而不必去修改任何已有的代码。

工厂方法模式是完全符合开闭原则的!使用工厂方法模式足以应付我们可能遇到的大部分业务需求。

缺点:

当产品种类非常多时,就会出现大量的与之对应的工厂类,这不应该是我们所希望的。

抽象工厂模式(Abstract Factory)   

使用场景:建议在产品种类非常多时,使用简单工厂模式与工厂方法模式相结合的方式来减少工厂类:即对于产品树上类似的种类(一般是树的叶子中互为兄弟的)使用简单工厂模式来实现。 (例如麦当当的不同汉堡类的产品),同一产品树非类似的品种使用工厂方法(例如麦当当的汉堡和可乐类的产品族)。

对于系统中存在不同的产品树,而且产品树上存在产品族,那么这种情况下就可能可以使用抽象工厂模式了。例如(麦当当的汉堡和肯德基的汉堡不同产品树中的同类产品)

角色分析:

抽象工厂角色:这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。在java中它由抽象类或者接口来实现。

具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。在java中它由具体的类来实现。

抽象产品角色:它是具体产品继承的父类或者是实现的接口。在java中一般有抽象类或者接口来实现。

具体产品角色:具体工厂角色所创建的对象就是此角色的实例。在java中由具体的类来实现。

与工厂方法涉及角色如出一辙。

//抽象产品角色

public interface Product {    

      void doProduct ();

}

//产品实例 麦当当的大可乐

public class MBigCola implements Product {

   public void doProduct ()

   {

        System.out.println(“do M BigCola ”);

   }

}

//产品实例 麦当当的小可乐

public class MSmallCola implements Product {

   public void doProduct ()

   {

        System.out.println(“do M SmalCola ”);

   }

}

//产品实例 KFC中的大可乐

public class KFCBigCola implements Product {

   public void doProduct ()   {

        System.out.println(“do KFC BigCola ”);

   }

}

//产品实例 KFC中的小可乐

public class KFCSmallCola implements Product {

   public void doProduct ()   {

        System.out.println(“do KFC SmallCola ”);

   }

}

//抽象工厂角色

public interface AbstractFoctory {    

    Product doProduct(String productName);

}

//麦当当的可乐工厂

public class MColaFactory implements AbstractFoctory {

    public Product doProduct( String productName) {

      if(“Big”.equals(productName)){

           return new MBigCola ();

      } else if(“Small”.equals(productName)){

           return new MSmallCola ();

      } else{

           return null;

      }

  }

}

//KCF的可乐生产工厂

public class KFCColaFactory implements AbstractFoctory {

    public Product doProduct(String productName) {

       if(“Big”.equals(productName)){

           return new KFCBigCola ();

       } else if(“Small”.equals(productName)){

           return new KFCSmallCola ();

       } else{

           return null;

    }

  }

}


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