设计模式——工厂模式

本文通过女娲造人的故事,深入浅出地介绍了工厂模式的概念、分类及其应用场景,包括简单工厂模式、工厂模式和抽象工厂模式,展示了如何利用工厂模式进行对象的创建,以及其在代码封装性和扩展性上的优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

工厂模式是个啥

工厂模式是用工厂方法代替new操作的一种模式,是我们最常用的实例化对象模式了,我们不暴露创建对象的具体逻辑,而是将逻辑封装在一个函数中,那么这个函数就可以被视为一个工厂。

工厂模式根据抽象程度不同可以分为

  • 简单工厂模式
  • 工厂模式
  • 抽象工厂模式

实际场景分析

上古之时,天地之间只有女娲一个人,不,只有它一个神。甚是孤单,于是女娲转念一想,这他娘的不是办法呀,得想办法造一些人来陪我玩,要不然无聊死了。于是女娲明确了工作目标:我要造人!

package DesignMode.FactoryMode;

/**
 * 女娲的目标是造人,但是还没有想好造什么颜色的人,造出来的人说什么语言
 */
public interface Human {
    /**
     * 每一个人种皮肤都有对应的颜色
     */
    public void getColor();

    /**
     * 每一个人种都可以说话
     */
    public void talk();
}

知道了工作目标之后,女娲又犯难了,我该咋造人呢,嘿嘿嘿…,当然是搞一个阴阳八卦炼丹炉,搞一个造人的配方了。

/**
 * 女娲造人的八卦炉,抽象工厂
 */
public abstract class AbstractHumanFactory {

    /**
     * 造人的抽象方法,其中的"T"表示的是,只要实现了Human接口的类都可以作为参数
     * 传入参数必须是Class类型,必须是Human的实现类。
     * @param c
     * @param <T>
     * @return
     */
    public abstract <T extends Human> T createHuman(Class<T> c);
}
**
 * 造人的配方,它得先继承了阴阳八卦炼丹炉
 */
public class HumanFactory extends AbstractHumanFactory {
    @Override
    public <T extends Human> T createHuman(Class<T> c) {
        Human human = null;
        try {
            //使用反射创建对象
            human = (Human) Class.forName(c.getName()).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return (T) human;
    }

这炉子也有了,配方也有了,接下来女娲就要开始造人了。第一次由于女娲经验不足,没有把握好火候,给烤的太轻了,于是造出来了白人

/**
 * 白人
 * @author lenovo
 */
public class WhiteHuman implements  Human {
    @Override
    public void getColor() {
        System.out.println("我是一个白人,我的皮肤是白色的");
    }

    @Override
    public void talk() {
        System.out.println("我是一个白人,我说英语");
    }
}

女娲十分不服气,既然火候轻了,那我多烤一会不就得了,于是…

/**
 * 黑人
 * @author lenovo
 */
public class BlackHuman implements Human {


    @Override
    public void getColor() {
        System.out.println("我是一个黑人,我的皮肤是黑色的");
    }

    @Override
    public void talk() {
        System.out.println("我是黑人,我说话谁都听不懂");
    }
}

妈耶,这一下把女娲下的不轻,竟然造出来一个黑兄弟,难受。女娲决定再接再厉,吸取前两次的经验教训,这个好好把握火候

/**
 * 黄种人
 * @author lenovo
 */
public class YellowHuman implements Human {
    @Override
    public void getColor() {
        System.out.println("我是一个黄种人,我的皮肤是黄色的");
    }

    @Override
    public void talk() {
        System.out.println("我是一个黄种人,我说中国话");
    }
}

嘿嘿嘿,还是这黄种人看着舒服,说话也好听。最后女娲总结了一下造人的方法,准备批量生产。
工厂模式图
AbstractHumanFactory是一个抽象类,定义了一个八卦炉具有的整体功能,HumanFactory为实现类,完成具体的任务——创建人类;Human接口是人类的总称,其三个实现类分别为三类人种;NvWa类是一个场景类,负责模拟这个场景,执行相关的任务。
我们定义的每个人种都有两个方法:getColor(获得人的皮肤颜色)和talk(交谈),

public static void main(String[] args) {
        //声明阴阳八卦炉
        AbstractHumanFactory yinyanglu = new HumanFactory();
        //女娲第一次造人,火候不足,于是白人产生了
        System.out.println("--造出的第一批人是白色人种--");
        Human whiteHuman = yinyanglu.createHuman(WhiteHuman.class);
        whiteHuman.getColor();
        whiteHuman.talk();
        //女娲第二次造人,火候过足,于是黑人产生了
        System.out.println("\n--造出的第二批人是黑色人种--");
        Human blackHuman = yinyanglu.createHuman(BlackHuman.class);
        blackHuman.getColor();
        blackHuman.talk();
        //第三次造人,火候刚刚好,于是黄色人种产生了
        System.out.println("\n--造出的第三批人是黄色人种--");
        Human yellowHuman = yinyanglu.createHuman(YellowHuman.class);
        yellowHuman.getColor();
        yellowHuman.talk();

    }
--造出的第一批人是白色人种--
我是一个白人,我的皮肤是白色的
我是一个白人,我说英语

--造出的第二批人是黑色人种--
我是一个黑人,我的皮肤是黑色的
我是黑人,我说话谁都听不懂

--造出的第三批人是黄色人种--
我是一个黄种人,我的皮肤是黄色的
我是一个黄种人,我说中国话

工厂模式的优点

  1. 良好的封装性,代码结构清晰,一个对象创建是由条件约束的。

  2. 工厂方法模式的扩展比较好,在增加产品类的情况下,只要适当的修改具体的工厂类或扩展一个工厂类。

  3. 屏蔽产品类,不需要关心产品类的具体逻辑和实现,只要接口不变。

  4. 实现解耦框架。

扩展

简单工厂模式

简单工厂模式
有所不同的是,去掉了AbstractHumanFactory抽象类,同时把createHuman方法设置为静态类型,简化了类的创建过程,变更的源码仅仅是HumanFactory和NvWa类。
运行结果没有发生变化,但是我们的类图变简单了,而且调用者也比较简单,该模式是工厂方法模式的弱化,因为简单,所以称为简单工厂模式(Simple Factory Pattern),也叫做静态工厂模式。在实际项目中,采用该方法的案例还是比较多的,其缺点是工厂类的扩展比较困难,不符合开闭原则,但它仍然是一个非常实用的设计模式

延迟初始化

何为延迟初始化?一个对象被消费完毕后,并不立刻释放,工厂类保持其初始状态,等待再次被使用。

public class ProductFactory {
        private static final Map<String,Product> prMap = new HashMap();
        public static synchronized Product createProduct(String type) throws Exception{
            Product product =null;
			//如果Map中已经有这个对象
            if(prMap.containsKey(type)){
                product = prMap.get(type);
            }else{
                if(type.equals("Product1")){
                    product = new ConcreteProduct1();
                }else{
                    product = new ConcreteProduct2();
                }
				//同时把对象放到缓存容器中
                prMap.put(type,product);
            }
            return product;
        }
    }

通过定义一个Map容器,容纳所有产生的对象,如果在Map容器中已经有的对象,则直接取出返回;如果没有,则根据需要的类型产生一个对象并放入到Map容器中,以方便下次调用。

延迟加载框架是可以扩展的,例如限制某一个产品类的最大实例化数量,可以通过判断Map中已有的对象数量来实现,这样的处理是非常有意义的,例如JDBC连接数据库,都会要求设置一个MaxConnections最大连接数量,该数量就是内存中最大实例化的数量。

延迟加载还可以用在对象初始化比较复杂的情况下,例如硬件访问,涉及多方面的交
互,则可以通过延迟加载降低对象的产生和销毁带来的复杂性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值