设计模式-简单工厂模式及应用

简单工厂模式

 工厂模式的定义:定义一个创建产品对象的工厂接口,将产品对象的实际创建工作推迟到具体子工厂类当中。这满足创建型模式中所要求的“创建与使用相分离”的特点。

按实际业务场景划分,工厂模式有 3 种不同的实现方式,分别是简单工厂模式、工厂方法模式和抽象工厂模式。下面将陆续讲解几种设计模式。

简单工厂模式(Simple Factory Pattern):定义一个工厂类,它可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类。

因为在简单工厂模式中用于创建实例的方法是静态(static)方法,因此简单工厂模式又被称为静态工厂方法(Static Factory Method)模式,它属于类创建型模式,但不属于GOF23种设计模式

角色
  • 简单工厂(SimpleFactory):是简单工厂模式的核心,负责实现创建所有实例的内部逻辑。工厂类的创建产品类的方法可以被外界直接调用,创建所需的产品对象

  • 抽象产品(Product):是简单工厂创建的所有对象的父类,负责描述所有实例共有的公共接口。

  • 具体产品(ConcreteProduct):是简单工厂模式的创建目标。
    在这里插入图片描述

代码案例

  • 抽象产品
public abstract class Mobile {	
	/**
	 * 生产手机
	 */
	public abstract void produce();
}
  • 具体产品 抽象产品具体实现
public class Iphone extends Mobile {
	@Override
	public void produce() {
		System.out.println("apple iphone mobile");
	}
}

public class Samsung extends Mobile{
	@Override
	public void produce() {
		System.out.println("samsung Galaxy mobile");	
	}
}
  • 简单工厂
public class SimpileFactory {
	
	public static Mobile getMobile(String type){
		if (type.equals("iphone")) {
			return new Iphone();
		}else if (type.equals("samsung")) {
			return new Samsung();
		}
		return null;
     }

    public static Mobile getMobileForRelect(@SuppressWarnings("rawtypes") Class clazz) {
	try {
	 return	(Mobile)Class.forName(clazz.getName()).newInstance();
	} catch (InstantiationException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	} catch (IllegalAccessException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	} catch (ClassNotFoundException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
	
	return null;
	}
}
  • client 使用方
public class Client {
	
	public static void main(String[] args) {
		Mobile mobile =  SimpileFactory.getMobile("iphone");
		mobile.produce();
	}

}

运行结果

apple iphone mobile

案例结构图
在这里插入图片描述

client通过传给工厂方法的手机类型来产生不同品牌的手机,这里我们还可以通过 反射的方式,传递具体的类型来获取手机对象实例。

public static Mobile getMobileForRelect(@SuppressWarnings("rawtypes") Class clazz) {
	try {
	 return	(Mobile)Class.forName(clazz.getName()).newInstance();
	} catch (InstantiationException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	} catch (IllegalAccessException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	} catch (ClassNotFoundException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
	
	return null;
	}
  • client 通过反射的方式获取对象
public static void main(String[] args) {
		Mobile mobile2 =  SimpileFactory.getMobileForRelect(Samsung.class);
		mobile2.produce();
	}

执行结果:

samsung Galaxy mobile

不管通过什么方式,我们只需要通过调用工厂方法就能获取到我们需要得到的对象。如果我们增加一种手机类型,假如我们增加华为手机,那么我们的工厂通过类型获取的对象的方式还是需要更改,这违背了“开闭原则”。 对于使用方来说的话,不管有多少个client,都无需修改代码,只需传入新的类型,即可获取新的对象。

优缺点

优点:

  • 工厂类包含必要的逻辑判断,可以决定在什么时候创建哪一个产品的实例;
  • 客户端可以免除直接创建产品对象的职责,很方便的创建出相应的产品;
  • 工厂和产品的职责区分明确客户端无需知道所创建具体产品的类名,只需知道参数即可。
  • 也可以引入配置文件,在不修改客户端代码的情况下更换和添加新的具体产品类

缺点:

  • 简单工厂模式的工厂类单一,负责所有产品的创建,职责过重,一旦异常,整个系统将受影响。且工厂类代码会非常臃肿,违背高聚合原则。
  • 使用简单工厂模式会增加系统中类的个数(引入新的工厂类),增加系统的复杂度和理解难度
  • 系统扩展困难,一旦增加新产品不得不修改工厂逻辑,在产品类型较多时,可能造成逻辑过于复杂
  • 简单工厂模式使用了 static 工厂方法,造成工厂角色无法形成基于继承的等级结构。
应用场景

  • 对于产品种类相对较少的情况,考虑使用简单工厂模式。
  • 使用简单工厂模式的客户端只需要传入工厂类的参数,不需要关心如何创建对象的逻辑,可以很方便地创建所需产品。
简单工厂模式的典型应用及源码分析

java.util包下Calendar类,他是一个抽象类,我们使用的时候,会通过 Calendar.getInstance()获取Calendar对象(子类对象),Calendar抽象类的子类有 BuddhistCalendarJapaneseImperialCalendarGregorianCalendar

public abstract class Calendar implements Serializable, Cloneable, Comparable<Calendar> {


public static Calendar getInstance()
    {
        return createCalendar(TimeZone.getDefault(), Locale.getDefault(Locale.Category.FORMAT));
    }


private static Calendar createCalendar(TimeZone zone,
                                           Locale aLocale)
    {
        //...略
        Calendar cal = null;

        if (aLocale.hasExtensions()) {
            String caltype = aLocale.getUnicodeLocaleType("ca");
            if (caltype != null) {
                switch (caltype) {
                case "buddhist":
                cal = new BuddhistCalendar(zone, aLocale);
                    break;
                case "japanese":
                    cal = new JapaneseImperialCalendar(zone, aLocale);
                    break;
                case "gregory":
                    cal = new GregorianCalendar(zone, aLocale);
                    break;
                }
            }
        }
        if (cal == null) {
            // ...
            if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") {
                cal = new BuddhistCalendar(zone, aLocale);
            } else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja"
                       && aLocale.getCountry() == "JP") {
                cal = new JapaneseImperialCalendar(zone, aLocale);
            } else {
                cal = new GregorianCalendar(zone, aLocale);
            }
        }
        return cal;
    }
}

截取了主要部分,Calendar抽象类在这里既充当了工厂角色,也充当了抽象产品角色,具体产品为Calendar子类充当。

✨✨ 欢迎🔔订阅个人的微信公众号 享及时博文更新
个人工作号
✨✨ 个人GitHub地址
GitHub

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值