- 创建型模式-工厂模式
在设计模式中,工厂模式可以说是非常实用的一种设计模式,利用抽象工厂模式解耦上层引用和底层实现,能极大的提高代码扩展性,后期维护起来不会一改就是几十个类了,来吧,好好的说道说道工厂模式。
我会尽可能详细阐述清楚该模式所表达的一种设计思想,结尾给出一个利用抽象工厂模式,创建中间层,提出一个开发中因为未解耦而造成维护困难的的解决方案。
- 注意:文章中阐述的三种工厂模式代码是隔离的,为了使类或接口命名贴切其功能,三类方式里,命名可能重复,如果想写代码完整跑一遍,请建立三个不同包,在对应的包下,去创建相应类或接口。
一、简单工厂模式
- 说明:简单工厂模式是属于创建型模式,又叫做静态工厂方法(Static Factory Method)模式,但不属于23种GOF设计模式之一。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式,可以理解为是不同工厂模式的一个特殊实现。
以手机为例来说明
- 定义一个接口,开机的时候,手机界面上,会显示该手机品牌。
- 此处定义的接口不使用“I”做前缀的这种形式,直接用“Phone”更加形象贴切,类似Map,List。
- 注意:接口的命名,返回值类型,传值类型都很重要,开发前要考虑好。
public interface Phone {
/**
* 实施开机操作的时候,返回手机品牌
* @return 手机品牌
*/
String startUp();
}
- 创建一个小米手机类,这个对象有“开机”功能,实现Phone接口,返回“小米”手机品牌
public class XiaoMiPhone implements Phone {
@Override
public String startUp() {
return "小米";
}
}
- 同上,创建一个华为手机类
public class HuaWeiPhone implements Phone {
@Override
public String startUp() {
return "华为";
}
}
- 创建手机工厂管理类
public class PhoneFactory {
private static Phone mPhone;
//根据品牌关键字获取相应手机对象
public static Phone createPhone(String Brand) {
switch (Brand) {
case "小米":
mPhone = new XiaoMiPhone();
break;
case "华为":
mPhone = new HuaWeiPhone();
break;
}
return mPhone;
}
}
- 使用
public void test() {
Phone xiaoMi = PhoneFactory.createPhone("小米");
Phone huaWei = PhoneFactory.createPhone("华为");
System.out.print(xiaoMi.startUp() + "\n");
System.out.print(huaWei.startUp() + "\n");
}
- 结果显示
小米
华为
- 总结下:
- 简单工厂模式就是把功能类,放进一个工厂类中管理,通过传入相应“关键字”,获取不同的功能类对象。
- 这里使用了接口,规范了功能类对外暴露的方法,获取对象时只需要使用接口去定义对象,通过工厂类去获取不同实现。
- 不使用接口定义接受:
- 如果某些实现类中,有创建特殊方法,接口定义公共方法无法满足,想使用此类特殊方法,使用该类的类型去接受创建的对象
- 如果只是使用接口,去接受其实现方法,便没法使用相应类中的特殊定义的方法
- 具体场景,可做相应变通
- 其实,使用接口规范后,简单工厂模式就和抽象工厂模式就十分相似了!
二、工厂模式
- 工厂模式区别与简单工厂模式的是,工厂模式不是用一个统一的工厂类来管理所有对象,而是每一个对象都有不同的工厂相对应。
继续以手机为例说明
- 为了让实例更加完整,此处将上述相同的代码再次复写一遍,为了不做复读机,相关说明省略。疑惑的翻阅下简单工厂模式。
- 定义手机接口
public interface Phone {
/**
* 实施开机操作的时候,返回手机品牌
* @return 手机品牌
*/
String startUp();
}
- 创建一个小米手机类
public class XiaoMiPhone implements Phone {
@Override
public String startUp() {
return "小米";
}
}
- 创建一个华为手机类
public class HuaWeiPhone implements Phone {
@Override
public String startUp() {
return "华为";
}
}
可以看到,底层逻辑实现接口方法方式,这边并未做改动。实际三种工厂模式,底层逻辑实现都用接口规范。
接下来,需要针对小米和华为手机这俩个实现类,去构建不同的工厂,这边用接口去规范不同的工厂类
- 手机工厂接口
public interface PhoneFactory {
/**
* 获取相关手机实例
* @return 返回实现接口Phone的实例
*/
Phone getPhone();
}
- 创建小米手机工厂
public class XiaoMiPhoneFactory implements PhoneFactory {
@Override
public Phone getPhone() {
return new XiaoMiPhone();
}
}
- 创建华为手机工厂
public class HuaWeiPhoneFactory implements PhoneFactory {
@Override
public Phone getPhone() {
return new HuaWeiPhone();
}
}
- 使用
public void test() {
PhoneFactory xiaoMiFactory = new XiaoMiPhoneFactory();
PhoneFactory huaWeiFactory = new HuaWeiPhoneFactory();
System.out.print(xiaoMiFactory.getPhone().startUp() + "\n");
System.out.print(huaWeiFactory.getPhone().startUp() + "\n");
}
- 结果显示
小米
华为
总结下:
- 这种针对每个对象,去建立不同工厂类,我个人感觉,有点佛了。
三、抽象工厂模式
- 抽象模式是对工厂模式的进一步优化,工厂类不单单只能创建一个对象,而是能创建一组对象。
- 在这里,大家可能存在一个疑惑,简单工厂不也是创建一组对象吗?是的,在这点上,俩者是非常非常相似的,区别在于:简单工厂模式是外部传值进去,以获取不同对象;抽象工厂模式直接通过方法获取对象,不需要传值(这里,你可能会想,这不就是把创建对象方法拆开,用不同的方法去标识吗? 这里面的门道还是不一样的,大家对比下,底下阐述的俩种方式,心里应该就有数了)。
继续以手机为例说明
- 为了用例完整性,继续写出所有代码
- 定义一个Phone接口
public interface Phone {
/**
* 实施开机操作的时候,返回手机品牌
* @return 手机品牌
*/
String startUp();
}
- 创建小米手机类
public class XiaoMiPhone implements Phone {
@Override
public String startUp() {
return "小米";
}
}
- 创建华为手机类
public class HuaWeiPhone implements Phone {
@Override
public String startUp() {
return "华为";
}
}
至此,三类工厂底层实现都是:实现共性接口。区别是是对工厂类的不同构建,下面来看看抽象工厂的工厂类构建。
- 咱们用俩方式来看看,中间工厂类来创建一组对象
1、第一种方式
- 定义一个接口,这个接口里面是获取一系列的手机品牌的实例
public interface PhoneBrand {
/**
* 获取小米手机实例
* @return
*/
Phone getXiaoMi();
/**
* 获取华为手机实例
* @return
*/
Phone getHuaWei();
}
- 实现抽象工厂的这个接口
public class PhoneFactory implements PhoneBrand {
@Override
public Phone getXiaoMi() {
return new XiaoMiPhone();
}
@Override
public Phone getHuaWei() {
return new HuaWeiPhone();
}
}
- 使用
public void test() {
PhoneBrand phoneBrand = new PhoneFactory();
Phone xiaoMi = phoneBrand.getXiaoMi();
Phone huaWei = phoneBrand.getHuaWei();
System.out.print(xiaoMi.startUp() + "\n");
System.out.print(huaWei.startUp() + "\n");
}
- 结果显示
小米
华为
2、第二种方式
- 在这里思考下,抽象工厂模式,是在工厂类里面创建一组对象,与外层交互,不是通过关键字去返回相应对象,而是通过某个共性方法去返回“符合条件的实例”。
- 这里假设一个场景:我们定义的手机对象,其中的开机功能,只在对应的手机上才会起作用(小米手机想开机,只能使用小米手机类中的开机方法,华为也是如此),在这里,假设此款手机是华为手机。
- 此处,我们不定义接口,直接创建抽象工厂类。
public class PhoneFactory {
private static Phone instance;
public static Phone getInstance() {
if("XiaoMi".equals(android.os.Build.BRAND))
{
return new XiaoMiPhone();
}
if("HuaWei".equals(android.os.Build.BRAND))
{
return new XiaoMiPhone();
}
return null;
}
public static Phone getSingleInstance() {
if (instance == null) {
synchronized (PhoneFactory.class) {
if("XiaoMi".equals(android.os.Build.BRAND))
{
instance = new XiaoMiPhone();
}
if("HuaWei".equals(android.os.Build.BRAND))
{
instance = new HuaWeiPhone();
}
instance = null;
}
}
return instance;
}
}
- 使用
public static void test() {
Phone phone = PhoneFactory.getInstance();
if (phone == null) return;
System.out.print(phone.startUp() + "\n");
}
- 结果显示
华为