Java工厂模式(随笔)

news2024/12/28 4:25:21

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

文章目录:

  1. 三大工厂模式介绍
  2. 特殊工厂模式介绍
    1. 容器工厂模式的特点
    2. 超级工厂模式的特点
  3. 三大工厂模式的优,缺点
  4. 三大工厂模式的适用场景
  5. 三大工厂模式以及超级工厂和容器工厂模式写法

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

                                            三大工厂都是哪些?
简单工厂模式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)创建扫描工具类

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();

    }
}

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

小总结:

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/609138.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

计算机网络第二章——物理层(上)

提示&#xff1a;男儿何不带吴钩&#xff0c;收取关山五十州 文章目录 2.1.1 物理层基本概念知识引导物理层接口特征 2.1.2 数据通信基础知识数据通信相关术语数据通信系统要考虑的问题三种通信方式串行传输&并行传输同步传输&异步传输 脑图时刻 2.1.3 数据通信基础知识…

Google Play上架aab保姆级教程(纯aab上架/已上架apk转aab上架)

0、上传密钥 & 应用签名密钥 “Google 会使用上传证书验证您的身份&#xff0c;并使用您的应用签名密钥为 APK 签名以进行分发” 以上为官方解释。 2021年8月起&#xff0c;上传google play的应用必须以aab格式&#xff0c;aab的签名流程要比之前apk的复杂一些。需要上传…

如何真正有效地应对项目中的需求变更?

需求变更在奉行唯快不破的互联网公司&#xff0c;可算程序员头号噩梦&#xff0c;“996”直接元凶。 阿里口号拥抱变化。既然需求变更无法被消灭&#xff0c;就要通过学习&#xff0c;掌握更好应对需求变更方法。 1 常见的需求变更流程 先要发起变更申请&#xff0c;由变更委…

从IO多路复用到redis线程模型

文章目录 Unix IO模型分类阻塞IO - Blocking IO非阻塞IO - NoneBlocking IOIO多路复用 - IO multiplexing信号驱动IO - signal driven IO异步IO - asynchronous IO同步与异步的定义阻塞与非阻塞的定义 IO多路复用有哪些实现IO多路复用的大致实现selectpollepoll redis的线程模型…

Python实战基础19-异常处理及程序调试

1、异常概述 在程序运行过程中&#xff0c;经常会遇到各种各样的错误&#xff0c;这些错误统称为“异常”。 这些异常有的是由于开发者将关键字敲错&#xff0c;这类错误产生的是SyntaxError:invalid syntax&#xff08;无效语法&#xff09;&#xff0c;这将直接导致程序不能…

3.二进制高可用安装k8s 1.23集群(生产级)

二进制高可用安装k8s集群(生产级) 本文档适用于kubernetes1.23 节点 Etcd Cluster Etcd是一个数据库,k8s做的一些变更啥的都会存到Etcd中 如果集群比较大建议与master节点分装,单独装Etcd master节点 master分为几个重要的组件 你所有的流量都会经过Kube-APIServer Co…

排序算法——希尔排序图文详解

文章目录 希尔排序基本思想整体插入思想预排序结论 代码实现实现代码直接插入排序与希尔排序的效率比较测试代码&#xff1a; 时间复杂度 希尔排序 注1&#xff1a;本篇是基于对直接插入排序法的拓展&#xff0c;如果对直接插入法不了解&#xff0c;建议先看看直接插入排序 注…

Learning C++ No.27 【布隆过滤器实战】

引言 北京时间&#xff1a;2023/5/31/22:02&#xff0c;昨天的计算机导论考试&#xff0c;三个字&#xff0c;哈哈哈&#xff0c;摆烂&#xff0c;大致题目都是一些基础知识&#xff0c;但是这些基础知识都是非常非常理论的知识&#xff0c;理论的我一点不会&#xff0c;像什么…

【自制C++深度学习框架】表达式层的设计思路

表达式层的设计思路 在深度学习框架中&#xff0c;Expression Layer&#xff08;表达式层&#xff09;是指一个通用的算子&#xff0c;其允许深度学习网络的不同层之间结合和嵌套&#xff0c;从而支持一些更复杂的操作&#xff0c;如分支之间的加减乘除&#xff08;elementAdd…

PyTorch 深度学习 || 专题二:PyTorch 实验框架的搭建

PyTorch 实验框架的搭建 1. PyTorch简介 PyTorch是由Meta AI(Facebook)人工智能研究小组开发的一种基于Lua编写的Torch库的Python实现的深度学习库&#xff0c;目前被广泛应用于学术界和工业界&#xff0c;PyTorch在API的设计上更加简洁、优雅和易懂。 1.1 PyTorch的发展 “…

Numpy---生成数组的方法、从现有数组中生成、生成固定范围的数组

1. 生成数组的方法 np.ones(shape, dtypeNone, orderC) 创建一个所有元素都为1的多维数组 参数说明: shape : 形状&#xff1b; dtypeNone: 元素类型&#xff1b; order &#xff1a; {‘C’&#xff0c;‘F’}&#xff0c;可选&#xff0c;默认值&#xff1a;C 是否在内…

BPMN2.0自动启动模拟流程

思路&#xff1a;BPMN的流程模拟启动&#xff0c;主要是通过生成令牌&#xff0c;并启动令牌模拟 流程模拟的开启需要关键性工具&#xff1a;bpmn-js-token-simulation&#xff0c;需要先行下载 注&#xff1a;BPMN2.0的流程模拟工具版本不同&#xff0c;启动方式也不一样&am…

Kafka某Topic的部分partition无法消费问题

今天同事反馈有个topic出现积压。于是上kfk管理平台查看该topic对应的group。发现6个分区中有2个不消费&#xff0c;另外4个消费也较慢&#xff0c;总体lag在增长。查看服务器日志&#xff0c;日志中有rebalance 12 retry 。。。Exception&#xff0c;之后改消费线程停止。 查…

chatgpt赋能python:Python实现数据匹配的方法

Python实现数据匹配的方法 在数据分析和处理中&#xff0c;经常需要将两组数据进行匹配。Python作为一门强大的编程语言&#xff0c;在数据匹配方面也有着其独特的优势。下面我们将介绍Python实现数据匹配的方法。 数据匹配 数据匹配通常指的是将两组数据根据某些特定的规则…

理解calico容器网络通信方案原理

0. 前言 Calico是k8s中常用的容器解决方案的插件&#xff0c;本文主要介绍BGP模式和IPIP模式是如何解决的&#xff0c;并详细了解其原理&#xff0c;并通过实验加深理解。 1. 介绍Calico Calico是属于纯3层的网络模型&#xff0c;每个容器都通过IP直接通信&#xff0c;中间通…

试验SurfaceFlinger 中Source Crop

在 SurfaceFlinger 中&#xff0c;Source Crop 是用于指定源图像的裁剪区域的一个概念。Source Crop 可以理解为是一个矩形区域&#xff0c;它定义了源图像中要被渲染到目标区域的部分。在 Android 中&#xff0c;Source Crop 通常用于实现屏幕分辨率适应和缩放等功能。 在 Sur…

【Java基础篇】逻辑控制练习题与猜数字游戏

作者简介&#xff1a; 辭七七&#xff0c;目前大一&#xff0c;正在学习C/C&#xff0c;Java&#xff0c;Python等 作者主页&#xff1a; 七七的个人主页 文章收录专栏&#xff1a;Java.SE&#xff0c;本专栏主要讲解运算符&#xff0c;程序逻辑控制&#xff0c;方法的使用&…

2023_Python全栈工程师入门教程目录

2023_Python全栈工程师入门教程 该路线来自慕课课程,侵权则删,支持正版课程,课程地址为:https://class.imooc.com/sale/python2021 学习路线以三个项目推动,一步步夯实技术水平&#xff0c;打好Python开发基石 目录: 1.0 Python基础入门 2.0 Python语法进阶 3.0 Python数据…

windows系统典型漏洞分析

内存结构 缓冲区溢出漏洞 缓冲区溢出漏洞就是在向缓冲区写入数据时&#xff0c;由于没有做边界检查&#xff0c;导致写入缓冲区的数据超过预先分配的边界&#xff0c;从而使溢出数据覆盖在合法数据上而引起系统异常的一种现象。 ESP、EPB ESP&#xff1a;扩展栈指针&#xff08…

React.memo()、userMemo 、 userCallbank的区别及使用

本文是对以下课程的笔记输出&#xff0c;总结的比较简洁&#xff0c;若大家有不理解的地方&#xff0c;可以通过观看课程进行详细学习&#xff1b; React81_React.memo_哔哩哔哩_bilibili React76_useEffect简介_哔哩哔哩_bilibili React136_useMemo_哔哩哔哩_bilibili Rea…