2、工厂模式(设计模式笔记)

工厂模式的主要作用就是实现了创建者和调用者的分离。

一、面向对象设计的基本原则

  • OCP(开闭原则,Open-Closed Principle):一个软件的实体应当对扩展开放,对修改关闭。
  • DIP(依赖反转原则,Dependency Inversion Principle):要针对接口编程,不要针对实现编程
  • LoD(迪米特法则,Law of Demeter):只与你直接的朋友通信,而避免和陌生人通信

二、应用场景

  • JDKCalendargetInstance方法
  • JDBCConnection对象的获取
  • HibernateSessionFactory创建Session
  • SpringIOC容器创建管理bean对象
  • XML解析时DocumentBuilderFactory创建解析器对象
  • 反射中Class对象的newInstance方法

三、详细分类

3.1 一般情况下

Car.java

package cn.itcast.day229.factory;
public interface Car {
    public void run();
}

Audi.java

package cn.itcast.day229.factory;
public class Audi implements Car {

    public void run() {
        System.out.println("奥迪汽车");
    }
}

Benz.java

package cn.itcast.day229.factory;
public class Benz implements Car {

    public void run() {
        System.out.println("奔驰汽车");
    }
}

说明:这里有一个Car接口,其有两个实现,一个是Audi,一个是Benz。当我们在不使用工厂的时候要用到这两个实现的时候需要这样,如下:

Client01.java

package cn.itcast.day229.factory;
//测试在不使用工厂模式的情况下,下面这个类就是调用者
//在使用的时候我们需要知道如何实例化对象,如果更复杂的情况就是实例化很麻烦的时候
//我们在使用的时候就很不方便,而且和各个子类耦合较紧,不利于扩展
public class Client01 {
    public static void main(String[] args) {
        Car c1 = new Audi();
        Car c2 = new Benz();
        c1.run();
        c2.run();
    }
}

说明:如上,可以看到我们必须要了解各个实现的具体方法,必须自己手工进行实例化,这样显然比较麻烦,下面我们看使用工厂的情况。

3.2 简单工厂模式(静态工厂模式)

用来生产同一等级结构中的任意产品(对于新增的产品,需要修改已有的代码)
SimpleCarFactory01.java

package cn.itcast.day229.factory;
//使用简单工厂模式,当然在后面如何我们想要扩展可能会需要修改一定的代码,所以简单工厂是有一点问题的
//但有时候这可以忽略(违背了开闭原则)
public class SimpleCarFactory01 {
    
    public static Car createCar(String type) {
        if ("奥迪".equals(type)) {
            return new Audi();
        } else if ("奔驰".equals(type)) {
            return new Benz();
        } else {
            return null;
        }
    }
}

Client02.java

package cn.itcast.day229.factory;
//简单工厂情况下,此时我们就不需要和相关的实现关联了
public class Client02 {
    public static void main(String[] args) {
        Car c1 = SimpleCarFactory01.createCar("奥迪");
        Car c2 = SimpleCarFactory01.createCar("奔驰");
        
        c1.run();
        c2.run();
    }
}

说明:可以看到如果我们使用了简单工厂模式,在使用的时候无须了解各个实现的详细方法,也无须了解实现类的具体实现。只需要使用工厂为我们生产我们需要的实例对象即可。当然简单工厂还有另一种实现方式,实质差不多,如下:
SimpleCarFactory02.java

package cn.itcast.day229.factory;
//第二种简单工厂模式,其实两种都差不多
public class SimpleCarFactory02 {
    public static Car createAudi(){
        return new Audi();
    }
    
    public static Car createBenz(){
        return new Benz();
    }
}

说明:这种实现的本质和之前的类似。但是简单工厂实现虽然用的较多,但是当我们要扩展对象实现的时候就需要对工厂内部代码进行相关的修改,所以这破坏了设计的开闭原则,当然有时候可以忽略。

3.2 工厂方法模式

用来生产同一等级结构中的固定产品(支持增加任意产品)。为了避免简单工厂模式的缺点,不完全满足OCP。工厂方法模式和简单工厂模式最大的不同在于,简单工厂模式只有一个(对于一个项目或者一个独立模块而言)工厂类,而工厂方法模式有一组实现了相同接口的工厂类。但是一般情况下我们还是使用简单工厂模式。
FactoryMethodCarFactory.java

package cn.itcast.day229.factory;
//工厂方法模式
public interface FactoryMethodCarFactory {
    public Car createCar();
}

说明:这里我们创建一个工厂的接口,然后为每个类的创建实现一个对应的工厂,由各个单独的工厂来完全各个实例。

BenzFactory.java

package cn.itcast.day229.factory;
public class BenzFactory implements FactoryMethodCarFactory {
    public Car createCar() {
        return new Benz();
    }
}

AudiFactory.java

package cn.itcast.day229.factory;
public class AudiFactory implements FactoryMethodCarFactory {
    public Car createCar() {
        return new Audi();
    }
}

Client03.java

package cn.itcast.day229.factory;
//使用工厂方法模式
public class Client03 {
    public static void main(String[] args) {
        Car c1 = new AudiFactory().createCar();
        c1.run();
    }
}

说明:可以看到我们需要相关类的实例的时候是使用各个对应的工厂去完成的,这里将工厂进行了区分,当然如果我们要对实现进行扩展就不会破坏设计原则了。如下:
Byd.java

package cn.itcast.day229.factory;
//增加一个比亚迪车,此时我们不需要修改其他代码,只需要增加一个比亚迪汽车工厂即可。
public class Byd implements Car {
    public void run() {
        System.out.println("比亚迪汽车");
    }
}

BydFactory.java

package cn.itcast.day229.factory;
public class BydFactory implements FactoryMethodCarFactory {

    @Override
    public Car createCar() {
        return new Byd();
    }
}

说明:可以看到这样我们就进行了扩展,无须对原来工厂中的方法中代码进行修改,这当然更好,但是维护起来却更复杂了。

3.3 抽象工厂模式

用来生产不同产品族的全部产品(对于新增的产品,无能为力,支持增加产品族)。是工厂方法模式的升级版本,在有多个业务品种、业务分类时,通过抽象工厂模式产生需要的对象是一种很好的解决方式。之前的情况是有一个接口和多个实现,但是有一种情况是有多个接口,每个接口又有多个实现,此时我们需要使用抽象工厂模式来解决。

例子:这里有发动机、座椅、轮胎三个产品族,也就是三个接口。而每个接口下面分别有高端和低端的实现,对于低端和高端的实现我们可以跟根据情况进行组合。

Engine.java

package cn.itcast.day231.AbstractFactory;
public interface Engine {
    
    public void run();
    public void start();
}

//高端发动机
class LuxuryEngine implements Engine{
    @Override
    public void run() {
        System.out.println("好发动机速度快");
    }

    @Override
    public void start() {
        System.out.println("好发动机启动快");
    }
}

//低端发动机
class LowEngine implements Engine{

    @Override
    public void run() {
        System.out.println("差发动机速度慢");
    }

    @Override
    public void start() {
        System.out.println("差发动机启动慢");
    }
}

Seat.java

package cn.itcast.day231.AbstractFactory;
//座椅接口
public interface Seat {
    public void nice();
}

//高端座椅
class LuxurySeat implements Seat{

    @Override
    public void nice() {
        System.out.println("高端座椅舒适度高");
    }
}

//低端座椅
class LowSeat implements Seat{

    @Override
    public void nice() {
        System.out.println("低端座椅舒适度低");
    }
}

Tyre.java

package cn.itcast.day231.AbstractFactory;
//轮胎
public interface Tyre {
    public void revole();
}

//高端轮胎
class LuxuryTyre implements Tyre{
    @Override
    public void revole() {
        System.out.println("高端轮胎防滑性好");
    }
}

//低端轮胎
class LowTyre implements Tyre{
    @Override
    public void revole() {
        System.out.println("低端轮胎防滑性差");
    }
}

说明:上面给出了几个产品族,也就是一辆汽车必须需要引擎、座椅、轮胎三类对象,我们需要工厂来创建一个实例对象。

LowCarFactory.java

package cn.itcast.day231.AbstractFactory;
//低端汽车工厂
public class LowCarFactory implements CarFactory {

    @Override
    public Engine createEngine() {
        return new LowEngine();
    }

    @Override
    public Seat createSeat() {
        return new LowSeat();
    }

    @Override
    public Tyre createTyre() {
        return new LowTyre();
    }
}

LuxuryCarFactory.java

package cn.itcast.day231.AbstractFactory;
//高端汽车工厂
public class LuxuryCarFactory implements CarFactory {

    @Override
    public Engine createEngine() {
        return new LuxuryEngine();
    }

    @Override
    public Seat createSeat() {
        return new LuxurySeat();
    }

    @Override
    public Tyre createTyre() {
        return new LuxuryTyre();
    }
}

说明:上面我们给处理高端汽车工厂和低端汽车工厂,当我们要使用时直接使用各自的工厂即可。

Client.java

package cn.itcast.day231.AbstractFactory;
//测试
public class Client {
    public static void main(String[] args) {
        CarFactory factory = new LuxuryCarFactory();
        Engine engine = factory.createEngine();
        engine.run();
        engine.start();
    }
}

说明:如上,如果我们需要一辆高端汽车,那么可以使用工厂直接生产我们需要的高端的引擎、座椅、轮胎。

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

推荐阅读更多精彩内容