深入浅出简单工厂模式

学简单工厂设计模式之前,让我们先来了解一下。首先抛出几个问题,什么是接口?接口有什么作用?接口如何使用?

接口是什么?

java中的接口类似于一个抽象类,或者叫它为一个特殊的抽象类,跟一般抽象类相比,接口所有的属性都是公有的,而且为常量,所有的方法都是抽象方法。也就是说,接口里面只有方法的定义,没有方法的实现。

用来干嘛?

通常用接口来定义实现类的外观,也就是定义实现类的行为,用来约束实现类的行为。接口相当于一份契约,根据外部应用需要的功能,约定了实现类应该要实现的功能,但是具体怎么实现并不是接口该关心的事。实现类出了必须实现接口规定的功能以外,也可以根据自身的需要自定义一些方法功能,也就是我们再日常开发中所了解到的,如果实现该接口,就必须就必须添加接口中定义的方法。
通过使用接口,可以实现不相关类的相同行为,而不需要考虑这些类之间的层次关系,接口就是实现类对外的 外观。

接口的思想

根据接口的作用与用途,总结下来就是一句话,“封装隔离”。
隔离就是外部调用与内部实现,外部调用只是通过外部接口进行调用,而外部调用是不知道具体实现的,也就是说外部调用与内部实现是被接口隔离开的。
封装就是对数据的封装,不需要了解其具体的实现,但是这里的封装是指“对被隔离体的行为的封装”,或者是“被隔离体的职责的封装”。

接口的好处

也就是说,接口是不用变的,如果需要实现相应的功能,就在接口实现类里面实现,而不需要修改接口 中的代码。而内部实现的变化就不会影响到外部应用,从而使得系统更加灵活,具有更好的扩展性和可维护性。

接口与抽象类的选择

1.优先选择接口
2.在既要定义子类行为,又要为子类提供公共的功能时应选择抽象类。

面向接口编程

在java程序设计里面,非常讲究分层和模块的划分。通常按照三层来划分java程序,分别为表现层、逻辑层和数据层,这些层之间都是通过接口来通讯。
在每个层里面,又有很多个小模块,每个小模块对外则是一个整体,所以一个模块对外应该提供接口,其他地方需要使用这个模块的功能时,可以通过接口进行调用。
在这里插入图片描述每一个层中,各个模块之间的交互要通过接口。如下图所示:
在这里插入图片描述
这里不用去抠细节,各个模块功能是什么?接口里的方法怎么定义?具体怎么实现等。仅仅学习其逻辑结构的设计模式。
上图说提到的组件,就是能够实现一定功能的封装体。小到一个类,大到一个系统,可以叫做组件。
我仔细想一想,小的系统放到大的系统中去,它也只能成为组件了,从设计的角度来看,系统、子系统、模块、组件其实都是一回事的。而且都是接口隔离体,具体如下图所示:
在这里插入图片描述

如果不使用设计模式

铺垫的有点长,但是为了更好地理解,如果不使用设计模式,我们怎么写代码?下面是我们的代码部分了。首先其整体思路就是:先创建一个接口类Api,一个接口实现类Impl和一个能够执行的访问的类。Clent。
在这里插入图片描述
下面直接上代码更加的明了,废话就少说了。
首先写一个接口

/**
接口类
**/
public interface Api {
	public void test(String s);
}

实现类,实现Api接口,作为Api的具体实现类

public class ImplA implements Api {
	@Override
	public void test(String s) {
		System.out.println("ImplA ==" + s);
	}
}

定义一个可以访问的客户端,Api

public class Client {

	public static void main(String[] args) {
		Api api = new ImplA();
		api.test("接口隔离原则");
	}
}

上面的写法有问题吗?
违反了接口的隔离封装原则,我们不仅仅知道接口,还知道它的实现类,也就是说客户端就不应该知道实现类ImplA。
简单工厂模式看看 。

解决方案-简单工厂模式

简单工厂模式的结构图,如下图所示,在原来的技术上加了一个Factory类,这个类封装了接口的具体实例化。
在这里插入图片描述
直接上代码后,更加简洁明了。
1.接口Api的定义:

public interface Api {
	public void test(String s);
}

2.定义实现Api接口的实现类ImplA,代码如下:

public class ImplA implements Api {
	@Override
	public void test(String s) {
		System.out.println("ImplA ==" + s);
	}
}

3.定义实现Api接口的实现类ImplB,代码如下:

public class ImplB implements Api {
	@Override
	public void test(String s) {
		System.out.println("Impl B" + s);
	}
}

4.定义一个封装具体接口实现的工厂类,SimpleFactory,代码具体如下:

public class SimpleFactory {
	public static Api createApi(int i) {
		Api api = null;
		if(i == 1) {
			api = new ImplA();
		}
		else if(i == 2) {
			api = new ImplB();
		}
		return api;
	}
}

5.定义一个客户端,通过简单工厂类访问接口,Client类,代码如下:

public class Client {
	public static void main(String[] args) {		
		Api api = SimpleFactory.createApi(1);
		api.test("wang");
	}
}

简单工厂的优缺点

优点:

1.帮助封装
简单工厂虽然很简单,但是非常友好地帮助我们实现了组件封装,然后让组件外部能真正面向接口编程。
2.解耦
通过简单工厂,实现了客户端和具体实现类的解耦。
如同上面的例子,客户端根本就不知道具体是有谁来实现,也不知道具体是如何实现的,客户端只是通过工厂获取它的需要的接口对象。

缺点:

1.可能增加客户端的复杂
如果通过客户端的参数来选择具体实现类,那么就必须让客户端能理解各个参数所代表的具体功能和意义,这样会增加客户端使用的难度,也部分暴露了内部实现,这种情况可以选择用配置方式实现。
2.不方便展开子工厂
私有化简单工厂的构造方法,使用静态方法来创建接口,也就不能通过写简单工厂类的子类来改变创建接口的行为了。
根据上述缺点所述,每一次添加一个实现类都会修改SimpleFactory类中的代码,这样也可以,但不是一个很好的实现方式,所以下面就用可配置的实现类。如果对于反射一点都不认识的话,建议去学一学反射,再看看代码就更加的易懂一点。

可配置简单工厂模式

1.首先建立一个properties文件。里面就定义了实现类的相对路径,利用反射将,inter.isolation.impl.ImplA创建一个实例对象。

ImplClass=inter.isolation.impl.ImplA

2.工厂类,通过反射创建实现类实例,如下面代码所示。这里踩过一个坑,properties文件需要放在SimpleFactory 类所在的目录下,不然返回空指针异常。

public class SimpleFactory {
	
	/**
	 * 具体创建Api的方法,根据配置文件的参数来创建接口
	 * return 返回创建好的实例对象
	 * @throws IOException 
	 */
	public static Api createApi() throws Exception {
		//直接读取配置文件来获取需要创建实例的类
		//至于如何读取properties,还有反射这里忽略掉了
		Properties properties = new Properties();
		InputStream in = null;
		in = SimpleFactory.class.getResourceAsStream("Factory.properties");
		properties.load(in);
		//实例化
		Api api = null;
		api = (Api)Class.forName(properties.getProperty("ImplClass")).newInstance();
		return api;
	}
}

最后还有客户端的调用。

public class Client {
	public static void main(String[] args) throws Exception {
		Api api = SimpleFactory.createApi();
		api.test("wang");
	}
}

最后想想我们之前遇到配置类,比如数据连接,可以在properties定义一些连接信息,然后就可以在xml文件中调用,用的大概就是这种思路,反射,单例与Properties的解析和IO流。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值