Java工厂模式(随笔)

本文详细介绍了Java中的工厂模式,包括简单工厂模式、工厂方法模式、抽象工厂模式,以及两种特殊工厂模式:超级工厂模式和容器工厂模式。每个模式的优缺点、适用场景和示例代码都进行了阐述,强调了这些模式在创建对象过程中的封装和解耦作用,以及如何通过模式的扩展来解决开闭原则的问题。
摘要由CSDN通过智能技术生成

目录

前言

一、三大工厂模式以及特殊工厂模式介绍

1、简单工厂模式简介(Simple Factory Pattern)

2、工厂模式简介   (Factory Pattern)

3、抽象工厂模式简介 (Abstract Factory)

二、特殊工厂模式介绍

1、超级工厂模式简介 (Super Factory Mode)

2、容器工厂模式简介 (Container Factory Mode)

三、三大工厂模式的优,缺点

1、简单工厂模式的优,缺点

2、工厂模式的提点的优,缺点

3、抽象工厂模式的优,缺点

4、超级工厂模式的优,缺点

5、容器工厂模式的优、缺点

四、三大工厂模式的适用场景

1、简单工厂模式的适用场景

2、工厂模式的适用场景

3、抽象工厂模式的适用场景

4、超级工厂模式的适用场景

5、容器工厂模式的适用场景

五、三大工厂模式以及容器工厂和超级工厂模式写法

1、简单工厂模式

2、工厂模式

3、抽象工厂模式

4、超级工厂

​编辑

5、容器工厂

小总结:


前言

Java工厂模式是一种创建型设计模式,它提供了一种将对象创建过程封装到一个单独的类中的方式,这个类就是被称为‘工厂类’,它根据特定的条件来决定应该创建哪个对象!

一、三大工厂模式以及特殊工厂模式介绍

                                            三大工厂都是哪些?
简单工厂模式Simple Factory Pattern
工厂模式   Factory Pattern
抽象工厂模式Abstract Factory
                                             特殊工厂都是哪些?
容器工厂模式Container Factory Mode
超级工厂模式Super Factory Mode

注意:

准确的来说工厂模式一共只有三种;但在我们程序员这里不止三种,还有两种,我们把它叫 ‘容器工厂模式’ 和 ‘超级工厂模式’  ;为什么它们没有增加到三大模式呢?因为它们都是基于‘简单工厂模式 ’扩展开辟出来的,解决了简单工厂模式存在违反开闭原则等弊端。

1、简单工厂模式简介(Simple Factory Pattern)

Java简单工厂模式是一种创建型设计模式,它提供了一个工厂类,用于根据传入的参数来决定创建哪种类的实例;它的核心思想就是:‘将对象创建的过程封装到工厂类中’;,这样使得客户端无需关心具体对象的创建细节的过程。通常情况下,工厂类会根据不同的参数或条件来决定创建哪种对象,这样客户端只需要知道自己需要什么对象,而不需要关心对象的创建过程!

2、工厂模式简介   (Factory Pattern

Java工厂模式是一种创建型设计模式,它提供了一个接口或抽象类,用于创建相关或依赖对象的家族,而不需要明确指定具体类。这样客户端代码就可以使用该接口创建所需的对象,而无需关心具体实现。它的核心思想就是:‘将对象创建的过程封装到工厂类中,与简单工厂模式不同的是,工厂模式通过定义接口或抽象来描述对象的创建过程’;因此,它也更加具有的灵活性和扩展性 !

3、抽象工厂模式简介 (Abstract Factory)

Java抽象工厂模式 是一种创建型设计模式,它提供了将相关或依赖对象的创建过程封装起来的方法,通过提供一个工厂接口来封装对象的创建过程,使得具体的工厂类可以动态地切换;它的核心思想就是:‘将对象的创建和使用分离开来,使得客户端不需要知道具体的实现细节’;因此可以使系统更加的灵活、易于维护和可扩展性!

二、特殊工厂模式介绍

1、超级工厂模式简介 (Super Factory Mode)

Java超级工厂模式是一种创建型设计模式,它是基于简单工厂模式扩展开辟出来的,解决了简单工厂模式违反开闭原则的弊端同时也解决了类个数的过多,同时还在容器工厂模式的基础上再次的优化!

2、容器工厂模式简介 (Container Factory Mode)

Java容器工厂模式是一种创建型设计模式,它是基于简单工厂模式扩展开辟出来的,解决了简单工厂模式违反开闭原则的弊端同时也解决了类个数的过多!

三、三大工厂模式的优,缺点

1、简单工厂模式的优,缺点

  •       简单工厂模式的优点
    • 简单易懂:简单工厂模式的实现相对较为简单,易于理解和使用;     

    • 解耦合:简单工厂模式可以将对象的创建与使用分离开来,降低了客户端代码和具体某类之间的耦合度;

  •       简单工厂模式的缺点
    • 可扩展性有限,一旦某类过多或者某产品变化频繁,就需要不断修改工厂类的代码,这样会导致工厂类变得过于庞大和复杂,可扩展性受到限制;
    • 违反开闭原则:简单工厂模式的扩展性较差,如果需要添加新的某产品,就需要修改工厂类的代码,这样就会违反开闭原则;

2、工厂模式的提点的优,缺点

  •       工厂模式的优点
    • 解耦合:工厂模式可以将对象的创建与使用分离开来,降低了客户端代码和具体某类之间的耦合度;

    • 集中控制:通过工厂模式,可以将某产品对象的创建集中在一个工厂类中进行管理和控制,从而更加方便地进行维护和升级;

    • 可扩展性好:不同于简单工厂模式,工厂方法模式和抽象工厂模式支持增加新的产品类型而不需要修改原有的代码,符合开闭原则,提高了系统的可扩展性;

    • 符合面向对象设计原则:工厂模式是一种典型的面向对象设计模式,符合“高内聚、低耦合”的设计原则,可以提高代码的可读性、可维护性和可重用性;

  •       工厂模式的缺点
    • 代码量增加:由于引入了工厂类,所以会增加一定的代码量;

    • 增加系统复杂度:工厂模式需要额外引入一个工厂类,增加了系统的复杂度;

3、抽象工厂模式的优,缺点

  •         抽象工厂模式的优点
    • 隐藏了具体产品的实现细节,客户端只需要关心抽象接口即可,使得客户端代码更加简洁易懂;
    • 可以轻松地替换某产品系列,只需要修改具体工厂类即可;
    • 符合开闭原则,增加新的某产品系列和某产品族时,不需要修改已有的代码,只需要添加新的具体工厂类即可;
  •         抽象工厂模式的缺点
    • 如果需要增加新的某产品等级结构,则需要同时修改抽象工厂接口和所有的具体工厂类,这时可能违背了开闭原则;

4、超级工厂模式的优,缺点

  •         超级工厂模式的优点
    • 根据完整类型动态的加载class并创建实例;
    • 利用反射机制完美的解决了简单工厂模式存在的开闭原则问题;
    • 结合反射机制和泛型,使得客户端代码更加简洁,代码更加具有灵动、维护、扩展性;
  •         超级工厂模式的缺点
    • 每调用一次就要创建一次,对资源的浪费;

5、容器工厂模式的优、缺点

  •         容器工厂模式的优点
    • 利用反射机制完美的解决了简单工厂模式存在的开闭原则问题;
    • 结合反射机制、泛型和注解,使得客户端代码更加简洁,代码更加具有灵动、维护、扩展性;
    • 单例容器:不会随意创建实例,只会创建一次(限于所在的容器工厂内),线程存在安全问题,但是很小,但是配合原型容器两者阴阳结合,完美;
    • 原型容器:存储实例的Class<?>,线程安全得到保障
  •         容器工厂模式的缺点
    • 暂时没有缺点了

四、三大工厂模式的适用场景

1、简单工厂模式的适用场景

  1. 需要创建的对象较少:如果需要创建的对象很多,那么简单工厂模式可能会变得很复杂,不易维护和扩展。

  2. 客户端只需要知道所需对象的类型:客户端不需要关心对象的创建过程,只需要知道所需对象的类型即可。

  3. 工厂类负责创建的对象比较简单:如果需要创建的对象非常复杂,那么简单工厂模式可能无法满足需求,此时可以考虑使用工厂方法模式或抽象工厂模式。

2、工厂模式的适用场景

  1. 需要创建的对象较多且复杂:如果需要创建的对象很多,并且它们之间存在较大差异,那么工厂模式可以帮助我们更好地管理对象的创建过程。

  2. 需要灵活地扩展对象的创建过程:如果需要增加新的产品类或者修改创建逻辑,那么工厂模式可以使得我们更加方便地进行扩展和修改。

  3. 客户端代码需要与具体类解耦:如果客户端代码需要使用具体类来创建对象,那么它们之间的耦合度会很高。通过使用工厂模式,我们可以将对象的创建过程封装在工厂类中,从而实现客户端代码与具体类的解耦。

3、抽象工厂模式的适用场景

  1. 当需要将请求的发送者和接收者解耦时,可以考虑使用抽象模式。

  2. 当存在多个对象可以处理同一个请求时,可以考虑使用抽象模式。

  3. 当需要动态地指定可以处理请求的对象时,可以考虑使用抽象模式。

4、超级工厂模式的适用场景

  1. 大佬看需求随便用

5、容器工厂模式的适用场景

  1. 大佬看需求使用

五、三大工厂模式以及容器工厂和超级工厂模式写法

注意:

这里以手机打电话形式进行案例展示

1、简单工厂模式

UML 类图

工厂类会根据不同的参数或条件来决定创建哪种对象,这样客户端只需要知道自己需要什么对象,而不需要关心对象的创建过程!

代码实现如下

1)首先是Phone接口

package edu.nf.product;

/**
 * @author 半杯可可
 * @date 2023/5/31
 * 抽象电话的接口
 */
public interface Phone {
    /**
     * 抽象的打电话的功能,有不同的实现类做具体的实现
     */
    void call();
}

2)创建几个实现接口的方法的手机类方便测试

 2.1、创建华为手机类

package com.lx.dom.simpleFactoryPattern.impl.pro;

import com.lx.dom.simpleFactoryPattern.dao.product.Phone;

/**
 * @author 半杯可可
 * @date 2023/5/31
 */
public class HuaweiPhone implements Phone {

    @Override
    public void call() {
        System.out.println("使用华为手机打电话");
    }
}

 2.2、创建IPhone手机类

package com.lx.dom.simpleFactoryPattern.impl.pro;

import com.lx.dom.simpleFactoryPattern.dao.product.Phone;

/**
 * @author 半杯可可
 * @date 2023/5/31
 */
public class IPhone implements Phone {

    @Override
    public void call() {
        System.out.println("使用Iphone打电话");
    }
}

2.3、创建MIphone手机类

package com.lx.dom.simpleFactoryPattern.impl.pro;

import com.lx.dom.simpleFactoryPattern.dao.product.Phone;

/**
 * @author 半杯可可
 * @date 2023/5/31
 */
public class MiPhone implements Phone {

    @Override
    public void call() {
        System.out.println("使用MiPhone打电话");
    }
}

3)创建简单工厂模式类

通过简单工厂模式类实现相关业务逻辑

package com.lx.dom.simpleFactoryPattern.impl;

import com.lx.dom.simpleFactoryPattern.dao.product.Phone;
import com.lx.dom.simpleFactoryPattern.impl.pro.HuaweiPhone;
import com.lx.dom.simpleFactoryPattern.impl.pro.IPhone;
import com.lx.dom.simpleFactoryPattern.impl.pro.MiPhone;

/***
 * @Date(时间)2023-05-31
 * @Author 半杯可可
 *
 * 简单工厂模式类
 */
public class SimpleFactoryPattern {
    /**
     * 简单的工厂
     * @param name 需要创建对象的名称
     * @return
     */
    public static Phone create(String name) {
        //根据输入对象名称判断返回相匹配的对象
        if("IPhone".equals(name)) {
            //返回对象
            return new IPhone();
        }else if("MiPhone".equals(name)) {
            return new MiPhone();
        }

        return null;
    }

}

代码测试:

package com.lx.dom.simpleFactoryPattern.impl;

import com.lx.dom.simpleFactoryPattern.dao.product.Phone;

/***
 * @Date(时间)2023-06-01
 * @Author 半杯可可
 */
public class Mains {
    public static void main(String[] args) {
        Phone phone = SimpleFactoryPattern.create("IPhone");
        phone.call();

        Phone phone2 = SimpleFactoryPattern.create("MiPhone");
        phone2.call();

    }
}

以上的代码就是遵循简单工厂模式设计的,它的核心思想就是:‘将对象的创建过程封装到工厂类中’;简单工厂设计本身是不合规的,为什么这么说了?打个比方:‘如果我想要实现另一个手机类打电话,那么我就要修改工厂类的代码’,问题来了,开闭原则的概念:‘扩展开放,对修改关闭’,我们修改了工厂类的源码,那么也就严重违反了开闭原则。为了解决这个存在的严重弊端,后来也就出现了工厂模式

2、工厂模式

UML 类图

 代码实现如下

1)首先是Phone接口

package edu.nf.product;

/**
 * @author 半杯可可
 * @date 2023/5/31
 * 抽象电话的接口
 */
public interface Phone {
    /**
     * 抽象的打电话的功能,有不同的实现类做具体的实现
     */
    void call();
}

2)再创建PhoneFactory接口

工厂方法可以解决简单工厂带来的开闭原则的问题,
 但是工厂方法只能创建一种产品,一个产品对应一个工厂
所以当产品过多的时候,会产生类爆炸的问题

package edu.nf.factory.method;

import edu.nf.product.Phone;

/**
 * @author 半杯可可
 * @date 2023/5/31
 * 工厂方法可以解决简单工厂带来的开闭原则的问题,
 * 但是工厂方法只能创建一种产品,一个产品对应一个工厂
 * ,所以当产品过多的时候,会产生类爆炸的问题
 */
public interface PhoneFactory {

    /**
     * 抽象的创建方法
     * @return
     */
    Phone create();
}

3)创建几个实现Phone接口的方法的手机工厂类方便便测试

 3.1、创建华为手机类

package com.lx.dom.simpleFactoryPattern.impl.pro;

import com.lx.dom.simpleFactoryPattern.dao.product.Phone;

/**
 * @author 半杯可可
 * @date 2023/5/31
 */
public class HuaweiPhone implements Phone {

    @Override
    public void call() {
        System.out.println("使用华为手机打电话");
    }
}

 3.2、创建IPhone手机类

package com.lx.dom.simpleFactoryPattern.impl.pro;

import com.lx.dom.simpleFactoryPattern.dao.product.Phone;

/**
 * @author 半杯可可
 * @date 2023/5/31
 */
public class IPhone implements Phone {

    @Override
    public void call() {
        System.out.println("使用Iphone打电话");
    }
}

3.3、创建MIphone手机类

package com.lx.dom.simpleFactoryPattern.impl.pro;

import com.lx.dom.simpleFactoryPattern.dao.product.Phone;

/**
 * @author 半杯可可
 * @date 2023/5/31
 */
public class MiPhone implements Phone {

    @Override
    public void call() {
        System.out.println("使用MiPhone打电话");
    }
}

4)创建几个实现PhoneFactory接口方法的类

4.1、MiPhoneFactory工厂类

package edu.nf.factory.method;

import edu.nf.product.MiPhone;
import edu.nf.product.Phone;

/**
 * @author 半杯可可
 * @date 2023/5/31
 */
public class MiPhoneFactory implements PhoneFactory {

    @Override
    public Phone create() {
        return new MiPhone();
    }
}

4.2、IPhoneFactory工厂类

package edu.nf.factory.method;

import edu.nf.product.IPhone;
import edu.nf.product.Phone;

/**
 * @author 半杯可可
 * @date 2023/5/31
 * 苹果手机工厂
 */
public class IPhoneFactory implements PhoneFactory {

    @Override
    public Phone create() {
        return new IPhone();
    }
}

4.3、HuaweiPhoneFactory工厂类

package edu.nf.factory.method;

import edu.nf.product.HuaweiPhone;
import edu.nf.product.Phone;

/**
 * @author 半杯可可
 * @date 2023/5/31
 * 华为手机工厂
 */
public class HuaweiPhoneFactory implements PhoneFactory {

    @Override
    public Phone create() {
        return new HuaweiPhone();
    }
}

代码测试:

package edu.nf;

import edu.nf.factory.method.IPhoneFactory;
import edu.nf.factory.method.MiPhoneFactory;
import edu.nf.factory.method.PhoneFactory;

/***
 * @Date 2023/5/31
 * @Author 半杯可可
 */
public class Main2 {

    public static void main(String[] args) {
        //对象依赖于抽象,抽象是接口,对象是工厂类
        PhoneFactory factory = new IPhoneFactory();
        //调用抽象方法返回一个对象IPhone
        factory.create().call();
    }
}

以上的代码就是遵循工厂模式创建的,但是工厂方法可以很好的解决开闭原则的问题,可是工厂方法只能创建一种产品,一种产品只能对应一种工厂;因此,当产品过多的时候,也就增加了复杂度,过多的类,也就造成了所谓的 ‘类爆炸’问题;为了解决这个问题,就又出现了‘抽象工厂模式’。

3、抽象工厂模式

UML 类图

 代码实现如下

1)首先是接口

1.1、AbstractFactory 抽象工厂接口

package edu.nf.factory.abstracts;

import edu.nf.product.Pad;
import edu.nf.product.Phone;

/**
 * @author 半杯可可
 * @date 2023/5/31
 * 抽象工厂
 */
public interface AbstractFactory {

    Phone createPhone();

    Pad createPad();
}

1.2、Phone抽象工厂接口

package edu.nf.product;

/**
 * @author 半杯可可
 * @date 2023/5/31
 * 抽象电话的接口
 */
public interface Phone {
    /**
     * 抽象的打电话的功能,有不同的实现类做具体的实现
     */
    void call();
}

1.3、Pad平板手机接口

package edu.nf.product;

/**
 * @author 半杯可可
 * @date 2023/5/31
 * 平板
 */
public interface Pad {

    void play();
}

2)创建相关类,实现相关接口方法

2.1、与AbstractFactory 抽象工厂接口相关的工厂类

UML 类图

AppleFactory类

package edu.nf.factory.abstracts;

import edu.nf.product.IPad;
import edu.nf.product.IPhone;
import edu.nf.product.Pad;
import edu.nf.product.Phone;

/**
 * @author 半杯可可
 * @date 2023/5/31
 */
public class AppleFactory implements AbstractFactory {

    @Override
    public Phone createPhone() {
        return new IPhone();
    }

    @Override
    public Pad createPad() {
        return new IPad();
    }
}

HuaweiFactory类

package edu.nf.factory.abstracts;

import edu.nf.product.HuaweiPad;
import edu.nf.product.HuaweiPhone;
import edu.nf.product.Pad;
import edu.nf.product.Phone;

/**
 * @author 半杯可可
 * @date 2023/5/31
 */
public class HuaweiFactory implements AbstractFactory {

    @Override
    public Phone createPhone() {
        return new HuaweiPhone();
    }

    @Override
    public Pad createPad() {
        return new HuaweiPad();
    }
}

XiaomiFactory类

package edu.nf.factory.abstracts;

import edu.nf.product.MiPad;
import edu.nf.product.MiPhone;
import edu.nf.product.Pad;
import edu.nf.product.Phone;

/**
 * @author 半杯可可
 * @date 2023/5/31
 */
public class XiaomiFactory implements AbstractFactory {

    @Override
    public Phone createPhone() {
        return new MiPhone();
    }

    @Override
    public Pad createPad() {
        return new MiPad();
    }
}

2.2、与Phone接口相关的实现类

UML 类图

IPhone类

package edu.nf.product;

/**
 * @author 半杯可可
 * @date 2023/5/31
 */
public class IPhone implements Phone{

    @Override
    public void call() {
        System.out.println("使用Iphone打电话");
    }
}

HuaweiPhone类

package edu.nf.product;

/**
 * @author 半杯可可
 * @date 2023/5/31
 */
public class HuaweiPhone implements Phone{

    @Override
    public void call() {
        System.out.println("使用华为手机打电话");
    }
}

MiPhonele类

package edu.nf.product;

/**
 * @author 半杯可可
 * @date 2023/5/31
 */
public class MiPhone implements Phone{

    @Override
    public void call() {
        System.out.println("使用MiPhone打电话");
    }
}

2.3、与Pad接口相关的实现类

UML 类图

IPad类

package edu.nf.product;

/**
 * @author 半杯可可
 * @date 2023/5/31
 */
public class IPad implements Pad {

    @Override
    public void play() {
        System.out.println("使用IPad玩游戏");
    }
}

MiPad类

package edu.nf.product;

/**
 * @author 半杯可可
 * @date 2023/5/31
 */
public class MiPad implements Pad {

    @Override
    public void play() {
        System.out.println("使用MiPad玩游戏");
    }
}

HuaweiPad类

package edu.nf.product;

/**
 * @author 半杯可可
 * @date 2023/5/31
 */
public class HuaweiPad implements Pad {

    @Override
    public void play() {
        System.out.println("使用HuaweiPad玩游戏");
    }
}

以上代码就是遵循抽象工厂模式创建的,它提供了将相关或依赖对象的创建过程封装起来的方法,通过提供一个工厂接口来封装对象的创建过程,使得具体的工厂类可以动态地切换;但如果需要增加新的某产品等级结构,则需要同时修改抽象工厂接口和所有的具体工厂类,这时可能违背了开闭原则;后来,程序员们觉得抽象工厂模式非常的麻烦,在思来想去,觉得简单工厂模式其实已经非常好了,也就是存在开闭原则的弊端,解决了开闭原则不就好了吗,干嘛还要搞那些呢?因此,程序员们就基于简单工厂模式扩展开辟了 超级工厂

4、超级工厂

注意:

超级工厂是程序员们根据简单工厂模式扩展开辟出来的!

UML 类图

代码实现如下:

1)首先是Phone接口

package com.lx.dom.inster;

/***
 * @Date(时间)2023-06-01
 * @Author 半杯可可
 *
 * 专门打电话的接口
 */
public interface Phone {
    void call() ;
}

1.1、与Phone接口相关的实现类

MiPhone类

package com.lx.dom.impl.pro;

import com.lx.dom.inster.Phone;

/***
 * @Date(时间)2023-06-01
 * @Author 半杯可可
 */
public class MiPhone implements Phone {
    @Override
    public void call() {
        System.out.println("我用MiPhone打电话");
    }
}

IPhon类

package com.lx.dom.impl.pro;

import com.lx.dom.inster.Phone;

/***
 * @Date(时间)2023-06-01
 * @Author 半杯可可
 */
public class IPhone implements Phone {
    @Override
    public void call() {
        System.out.println("我用IPhone打电话");
    }
}

2)创建超级工厂类

package com.lx.dom.supers;

import java.lang.reflect.InvocationTargetException;

/***
 * @Date(时间)2023-06-01
 * @Author 半杯可可
 *
 * 超级工厂(简单工厂 + 反射 + 泛型),利用反射机制解决开闭原则的问题
 */
public class SuperFactorys {

    /**
     * 根据完整类型名动态加载class并创建实例
     * @param className
     * @return
     */
    public static <T> T create(String className) {

        try {
            //动态加载class
            Class<?> clazz = Class.forName(className);

            //通过calss对象获取构造函数创建新实例
            T instance = (T) clazz.getConstructor().newInstance();
            return instance ;
        } catch (Exception e) {

            //异地重抛
            throw new RuntimeException("Create instance fail.",e);
        }
    }

}

3)测试代码

package com.lx.dom;

import com.lx.dom.inster.Phone;
import com.lx.dom.supers.SuperFactorys;

/***
 * @Date(时间)2023-06-01
 * @Author 半杯可可
 */
public class Mains {

    public static void main(String[] args) {
        //com.lx.dom.impl.pro这一段是包名,IPhone是类名,不能输错
        Phone phone = SuperFactorys.create("com.lx.dom.impl.pro.MiPhone") ;
        phone.call();
    }
}

以上代码就是根据基于简单工厂模式扩展出来的超级工厂模式写的,超级工厂模式利用反射机制完美的解决了简单工厂模式存在的开闭原则的问题;结合了反射机制和泛型,也使得客户端代码更加的简洁,代码更具有灵动性、可维护性和扩展性!

5、容器工厂

注意:

容器工厂是程序员们根据简单工厂模式扩展开辟出来的!

UML 类图

代码实现如下:

1)首先是Phone接口

package com.lx.dom.inster;

/***
 * @Date(时间)2023-06-01
 * @Author 半杯可可
 *
 * 专门打电话接口
 */
public interface Phone {

    void call();
}

创建@Bean注解

package com.lx.dom.anno;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/***
 * @Date(时间)2023-06-01
 * @Author 半杯可可
 *
 * 注解接口
 */
//注解只能用在类上
@Target(ElementType.TYPE)

//注解一直保留
@Retention(RetentionPolicy.RUNTIME)
public @interface Bean {


    /**
     * 声明一个Value属性,用来定义Bean别名
     * 声明容器(集合)Map key键
     * @return
     */
    String value () ;

    /**
     * 用来标识注解容器保存对象是否是单例,true是单例容器,false则是原型容器
     * @return
     */
    boolean scope() default  true ;

}

1.1、与Phone接口相关的实现类

HUAEPhone类

package com.lx.dom.iml.pro;

import com.lx.dom.anno.Bean;
import com.lx.dom.inster.Phone;

/***
 * @Date(时间)2023-06-01
 * @Author 半杯可可
 */
@Bean(value = "HUAEPhone",scope = false)
public class HUAEPhone implements Phone {
    @Override
    public void call() {
        System.out.println("我在使用HUAEPhone打电话");
    }
}

IPhone类

package com.lx.dom.iml.pro;

import com.lx.dom.anno.Bean;
import com.lx.dom.inster.Phone;

/***
 * @Date(时间)2023-06-01
 * @Author 半杯可可
 */
@Bean(value = "IPhone",scope = true)
public class IPhone implements Phone {
    @Override
    public void call() {
        System.out.println("我在使用IPhone打电话");
    }
}

2)创建扫描工具类

<dependencies>
    <!-- 创建扫描,所需要的依赖Jar包 -->
    <dependency>
        <groupId>io.github.classgraph</groupId>
        <artifactId>classgraph</artifactId>
        <version>4.8.158</version>
    </dependency>
</dependencies>
package com.lx.dom.util;

import io.github.classgraph.ClassGraph;
import io.github.classgraph.ScanResult;

import java.util.List;

/***
 * @Date(时间)2023-06-01
 * @Author 半杯可可
 *
 * 注解扫描器,工具类
 */
public class ScanUtils {


    /***
     * 扫描指定的包,并且返回class对象
     * @param parameter 不定长参数
     * @return
     */
    public static List<Class<?>> scan (String...parameter) {

        //一、创建核心类图对象
        ClassGraph classGraph = new ClassGraph() ;

        //二、启用所有扫描机制
        classGraph.enableAllInfo() ;

        //三、设置要扫描包的路径
        classGraph.acceptPackages(parameter) ;

        //四、执行并返回扫描的结果集
        try(ScanResult result = classGraph.scan()) {

            //五、从结果集中获取所有的Class信息,加载到JVM中
            return result.getAllClasses().loadClasses() ;

        }catch (Exception e) {
            throw new RuntimeException("解析失败",e) ;
        }

    }

    //测试一下
    public static void main(String[] args) {
        List<Class<?>> list = scan("com.lx.dom") ;
        list.forEach(System.out::println);
    }

}

3)创建容器工厂类

package com.lx.dom.factory;

import com.lx.dom.anno.Bean;
import com.lx.dom.util.ScanUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/***
 * @Date(时间)2023-06-01
 * @Author 家辉
 *
 *核心容器类
 *
 */
public class ContainerFactory {

    //创建单例容器
    private static Map<String,Object> singleton = new HashMap<>() ;

    //创建原型容器
    private static Map<String,Class<?>> prototype = new HashMap<>() ;

    /**
     * 扫描容器
     * @param parameter
     */
    public ContainerFactory(String...parameter) {

        //执行扫描,返回class集合
        List<Class<?>> list = ScanUtils.scan(parameter) ;

        //解析有的class对象,找到所有带有注解的类
        resolveClass(list);
    }


    /***
     * 解析有的class对象,找到所有带有注解的类
     * @param list
     */
    public void resolveClass (List<Class<?>> list) {
        //遍历List集合
        list.forEach(clazz->{

            //判断是否获取到注解
            if(clazz.isAnnotationPresent(Bean.class)){

                //获取注解的Value属性
                String value = clazz.getAnnotation(Bean.class).value();

                //判断注解是否为true,如果为ture则返回单例反之原型容器
                if(clazz.getAnnotation(Bean.class).scope()){

                    //通过class构建函数新建实例
                   Object ins = newInstance(clazz) ;

                   //将实例存储到容器中(map集合)
                    singleton.put(value,ins) ;

                }else{
                    //如果为false则返回原型
                    prototype.put(value,clazz) ;
                }

            }


        });


    }


    //根据calss对象创建实例
    private Object newInstance(Class<?> clazz) {

        try {
            //返回新建实例
            return clazz.getConstructor().newInstance() ;

        }catch (Exception e) {
            throw new RuntimeException("解析失败",e) ;
        }
    }



    //创建泛型方法专门从容器中获取对象
    public <T> T getBean(String name) {
        //获取单例,如果不是则返回原型
        Object instan = singleton.get(name) ;
        if(instan == null){
            //否则返回原型
            Class<?> type = prototype.get(name) ;

            //新建实例
            instan = newInstance(type);
        }

        //返回单例
        return (T) instan ;
    }

}

4)代码测试

package com.lx.dom;

import com.lx.dom.factory.ContainerFactory;
import com.lx.dom.inster.Phone;

/***
 * @Date(时间)2023-06-01
 * @Author 半杯可可
 */
public class Mains {

    public static void main(String[] args) {
        

        // com.lx.dom 这是包名,不能输错
        ContainerFactory  factory = new ContainerFactory("com.lx.dom");
    
        // HUAEPhone 这是注解名,不能输错
        Phone phone = factory.getBean("HUAEPhone") ;
        System.out.println(phone);

        Phone phone2 = factory.getBean("IPhone") ;
        System.out.println(phone2);

        phone2.call();
        phone.call();

    }
}

以上代码就是根据基于简单工厂模式扩展出来的容器工厂模式写的,这个模式是工厂模式最顶级的了;

小总结:

它们都有一个共同点,那就是:‘它们都是创建型设计模式’ ;值得注意的是,它们就像是一种等级,发现没有?简单工厂模式——>工厂模式——>抽象工厂模式——>超级工厂模式——>容器工厂模式;它们都在不断的优化提升;简单工厂模式有违反开闭原则的弊端,为了解决这一个弊端然后出现了工厂模式,它的出现完美的解决了简单工厂模开闭原则可是它又有问题了,工厂模式类的个数太多,增加了复杂度,为了解决这个问题,就又出现了个抽象工厂,它的出现就完美的解决了开闭原则和类过多的弊端,但是抽象工厂模式 还是不够完美,程序员们思来想去,觉得简单工厂模式其实已经很好了,也就是存在开闭原则的弊端,解决了开闭原则不就好了吗,干嘛还要搞那些呢?因此,程序员们就基于简单工厂模式扩展开辟了超级工厂模式 ,可是它还是不够完美,最终再次扩展开辟出了容器工厂模式

评论 38
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

半杯可可

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值