设计模式之"工厂模式"

这是我设计模式系列的第一篇总结。
首先讲一下为什么需要使用工厂设计模式?
我们平时正常开发编码的时候创建对象有几种方式:
1.直接new
2.使用Class类的newInstance方法
3.使用Constructor类的newInstance方法
4.使用clone
5.使用序列化
最常见的就是第一种new的方式。但是有的时候往往创建对象和使用对象在同一个类当中。这就导致了这个类的任务很繁重,并且职责不清晰。并且违反了"开闭原则"。所以我们就要把创建对象和使用对象两个职责分离开,这样我们就引入了“工厂”的概念。我们把创建对象的任务交给“工厂”来做,什么时候用就直接从工厂中拿。
我们常说的工厂设计模式有“简单工厂模式”、“工厂模式”、和“抽象工厂模式”。
工厂三兄弟我从简单到复杂(简单到抽象)进行总结。

一.简单工厂模式

简单工厂模式定义如下:

简单工厂模式(Simple Factory Pattern):定义一个工厂类,它可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类。因为在简单工厂模式中用于创建实例的方法是静态(static)方法,因此简单工厂模式又被称为静态工厂方法(Static Factory Method)模式,它属于类创建型模式。


我们围绕着一个购买Nike和Adidas产品的例子实现接下来的三种工厂模式。
首先简单工厂模式顾名思义他的结构比较简单,那么适用于需要的对象比较少并且简单的情况下。

简单工厂

1.Shoes 抽象产品接口:这个接口代表了所有工厂最终生产出具体类的父类。
2.NikeShoes、AdidasShoes 具体产品实现类:抽象产品接口的实现类,这里包含了具体方法的实现、自己的构造方法、初始化一些信息等。
3.ShoesFactory 工厂方法类:整个当中最核心的类。此类包含了选择创建对象的逻辑。

//抽象产品接口
public interface Shoes {
     //共有方法
     void display();
}

//Nike商品
public class NikeShoes implements Shoes {
    @Override
    public void display() {
        System.out.println("耐克鞋~~~");
    }
}
//Adidas商品
public class AdidasShoes implements Shoes {
    @Override
    public void display() {
        System.out.println("阿迪达斯鞋~~~");
    }
}

//工厂
public class ShoesFactory {
    public static Shoes getShoes(String brand) {
        if (brand.equalsIgnoreCase("nike")) {
            return new NikeShoes();
        } else if (brand.equalsIgnoreCase("adidas")) {
            return new AdidasShoes();
        } else {
            return null;
        }

    }
}
//购买鞋子入口函数
public class BuyShoes {
    public static void main(String args[]) {
        Shoes shoes = ShoesFactory.getShoes("nike");
        shoes.display();
    }
}


//输出 
-------------
//耐克鞋~~~

我们可以看到这个工厂类通过传入的参数来选择创建具体类型的对象并且返回。

二.工厂方法模式

接下来是工厂三兄弟的老二——“工厂方法模式”。
这个老二又是怎样的需求促使它诞生的呢?
我们回忆一下刚才的老三"简单工厂模式",它适用于创建的对象类型较少的情况下。但是它有一个致命的缺点就是工厂类中的任务太重了,如果对象的类型较多,则需要写很多的if... else...,如果某一个类型改变了,就要回过头来去修改工厂中的逻辑代码,这样很不方便。把简单工厂稍微抽象一下,就诞生了我们的工厂方法模式来解决这样的问题。
工厂方法模式定义:

工厂方法模式(Factory Method Pattern):定义一个用于创建对象的接口,让子类决定将哪一个类实例化。工厂方法模式让一个类的实例化延迟到其子类。工厂方法模式又简称为工厂模式(Factory Pattern),又可称作虚拟构造器模式(Virtual Constructor Pattern)或多态工厂模式(Polymorphic Factory Pattern)。工厂方法模式是一种类创建型模式。


工厂方法模式

1.ShoesFactory 抽象工厂:有别于简单工厂这里多了一个“抽象工厂”接口。接口中声明了创建具体产品的方法。返回值是抽象的产品接口类型。
2.NikeShoesFactory、AdidasShoesFactory 具体工厂类:实现抽象工厂接口,并实现创建对象的方法,各个不同的具体工厂生产自己的具体产品。
3.产品接口和实现类与简单工厂几乎相同。

package Factory;
//抽象商品接口
public interface Shoes {
     void display();
}

//Nike商品实现类
public class NikeShoes implements Shoes {
    @Override
    public void display() {
        System.out.println("耐克鞋~~~");
    }
}

//Adidas商品实现类
public class AdidasShoes implements Shoes {
    @Override
    public void display() {
        System.out.println("阿迪达斯鞋~~~");
    }
}

//抽象工厂
public interface ShoesFactory {
     Shoes getShoes();
}


//  Nike工厂
public class NikeShoesFactory implements ShoesFactory {

    @Override
    public Shoes getShoes() {
        return new NikeShoes();
    }
}

//  Adidas工厂
public class AdidasShoesFactory implements ShoesFactory {
    @Override
    public Shoes getShoes() {
        return new AdidasShoes();
    }
}

//购买函数
public class BuyShoes {
    public static void main(String args[]) {
        ShoesFactory nikeShoesFactory = new NikeShoesFactory();
        Shoes nikeShoes =  nikeShoesFactory.getShoes();
        nikeShoes.display();
        ShoesFactory adidasShoesFactory = new AdidasShoesFactory();
        Shoes adidasShoes =  adidasShoesFactory.getShoes();
        adidasShoes.display();
    }
}

//输出
-----------
//耐克鞋~~~
//阿迪达斯鞋~~~

我们可以看到这种优化后的模式具体的产品从相对应的具体工厂生产,如果有新的产品,就横向增加新的工厂即可,删除同理不会横向纵向的影响代码结构,满足的了"开闭原则"。
那么我们想想这样的模式还存在什么弊端呢?

三.抽象工厂

工厂三兄弟的老大,也是真正Gof23种设计模式之一的"抽象工厂"模式。
定义:

抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。抽象工厂模式又称为Kit模式,它是一种对象创建型模式。

假设现在对象类型变得复杂横向纵向两个纬度都要扩展?如下图所示。


升级后的需求

按照老二工厂方法模式的思想。定义一个抽象工厂接口,每一个具体商品会实现对应的工厂类,那么就有了2*3=6种工厂类,如果在继续扩展工厂实现类会变得很多很繁杂,所以为了解决这种问题,我们在工厂方法模式上再抽象一层概念。

抽象工厂模式

这样我们只需要两个具体工厂就能生产6种产品了。

//抽象产品——鞋子
public interface Shoes {
     void displayShoes();
}

//抽象产品——裤子
public interface Pants {
    void displayPants();
}

//抽象产品——衣服
public interface Clothes {
    void displayClothes();
}

//具体产品——耐克鞋子
public class NikeShoes implements Shoes {
    @Override
    public void displayShoes() {
        System.out.println("耐克鞋~~~");
    }
}
//具体产品——耐克衣服
public class NikeClothes implements Clothes {
    @Override
    public void displayClothes() {
        System.out.println("耐克衣服~~~");

    }
}
//具体产品——耐克裤子
public class NikePants implements Pants {
    @Override
    public void displayPants() {
        System.out.println("耐克裤子~~~");

    }
}
//具体产品——阿迪鞋子
public class AdidasShoes implements Shoes {
    @Override
    public void displayShoes() {
        System.out.println("阿迪达斯鞋子~~~");

    }
}
//具体产品——阿迪衣服
public class AdidasClothes implements Clothes{
    @Override
    public void displayClothes() {
        System.out.println("阿迪达斯衣服~~~");
    }
}
//具体产品——阿迪裤子
public class AdidasPants implements Pants {
    @Override
    public void displayPants() {
        System.out.println("阿迪达斯裤子~~~");

    }
}

//抽象工厂
public interface AbstractFactory {
    Shoes getShoes();
    Clothes getClothes();
    Pants getPants();
}
//耐克工厂
public class NikeFactory implements AbstractFactory {
    @Override
    public Shoes getShoes() {
        return new NikeShoes();
    }

    @Override
    public Clothes getClothes() {
        return new NikeClothes();
    }

    @Override
    public Pants getPants() {
        return new NikePants();
    }
}
//阿迪工厂
public class AdidasFactory implements AbstractFactory {
    @Override
    public Shoes getShoes() {
        return new AdidasShoes();
    }

    @Override
    public Clothes getClothes() {
        return new AdidasClothes();
    }

    @Override
    public Pants getPants() {
        return new AdidasPants();
    }
}
public class Shopping {
    public static void main(String args[]) {
        AbstractFactory nikeFactory = new NikeFactory();//可通过配置文件获得
        Shoes nikeShoes = nikeFactory.getShoes();
        nikeShoes.displayShoes();
        Clothes nikeClothes = nikeFactory.getClothes();
        nikeClothes.displayClothes();

        AbstractFactory adidasFatory = new AdidasFactory();
        Shoes adidasShoes = adidasFatory.getShoes();
        adidasShoes.displayShoes();
        Pants adidasPants = adidasFatory.getPants();
        adidasPants.displayPants();
    }
}
//输出
-------------------
//耐克鞋~~~
//耐克衣服~~~
//阿迪达斯鞋子~~~
//阿迪达斯裤子~~~

例子虽然简单,但是想要应用实际用的好还是需要多加练习的。越抽象的方法越难理解但应用越广泛。抽象工厂方法也有缺点。它不适合架构设计好后频繁修改,因为横向纵向都扩展了以后必然存在“牵一发而动全身”的影响。所以要想把设计模式应用的巧妙灵活,真的是一门需要慢慢修炼的“内功”

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

推荐阅读更多精彩内容

  • 设计模式概述 在学习面向对象七大设计原则时需要注意以下几点:a) 高内聚、低耦合和单一职能的“冲突”实际上,这两者...
    彦帧阅读 3,733评论 0 14
  • 工厂模式是最常用的一类创建型设计模式,之前一直以为工厂模式只是23中设计模式中的一种,重新了解才知道这个模式还要细...
    晨鸣code阅读 1,262评论 0 6
  • 设计模式汇总 一、基础知识 1. 设计模式概述 定义:设计模式(Design Pattern)是一套被反复使用、多...
    MinoyJet阅读 3,884评论 1 15
  • 在面向对象编程中, 最通常的方法是一个new操作符产生一个对象实例,new操作符就是用来构造对象实例的。但是在一些...
    聂叼叼阅读 3,962评论 2 16
  • 1. 简单工厂 简单工厂模式又称为静态工厂模式,它属于创建型模式。在简单工厂模式中,可以根据不同的参数返回不同类的...
    落英坠露阅读 211评论 0 1