一、工厂设计模式
1.1简介
在Java中有三大设计模式,工厂设计模式,代理设计模式,单例设计模式。
工厂设计模式出现的目的是为了解决接口对象实例化的处理问题。
通过如下代码来观察:
interface IMessage{
public String getContent();
}
class NetMessage implements IMessage{
@Override
public String getContent() {
return "【网络消息】今天不用学习了 睡觉吧";
}
}
public class TestFactory { //主类
public static void main(String[] args) { //主方法
IMessage msg = new NetMessage();
System.out.println(msg.getContent());
}
}
程序执行结果:
【网络消息】今天不用学习了 睡觉吧
在大部分情况下只要拥有了接口和子类,那么首先应该想到的就是利用接口子类进行接口实例化对象的处理
客户端只关注具体的消息内容(今天不用学习了 睡觉吧),而不关注具体的消息类型是什么(网络消息,电视消息,报纸消息);
但是使用new 关键字 就会带来问题 此时客户端不仅要处理消息内容 还要去处理消息类型。
此时的程序是利用了关键字“new”直接在客户端上进行了指定接口对象的实例化处理,而这样一来就造成了接口与指定子类之间的耦合问题。 IMessage msg = new NetMessage();
,在以后的开发设计里面,关键字new是一个系统上最好用的对象实例化方式,但是也是耦合产生的最大元凶。,所有此时可以引入一个专门的过渡类,这个类负责接口对象的实例化生成。这个类即“工厂类”。
1.2什么是耦合?
耦合性是程序结构中各个模块之间相互关联的度量。它取决于各个模块之间的接口的复杂程度、调用模块的方式以及哪些信息通过接口。
耦合可以分为以下几种,它们之间的耦合度由高到低排列如下:
(1) 内容耦合。当一个模块直接修改或操作另一个模块的数据时,或一个模块不通过正常入口而转入另一个模块时,这样的耦合被称为内容耦合。内容耦合是最高程度的耦合,应该避免使用之。
(2) 公共耦合。两个或两个以上的模块共同引用一个全局数据项,这种耦合被称为公共耦合。在具有大量公共耦合的结构中,确定究竟是哪个模块给全局变量赋了一个特定的值是十分困难的。
(3) 外部耦合 。一组模块都访问同一全局简单变量而不是同一全局数据结构,而且不是通过参数表传递该全局变量的信息,则称之为外部耦合。
(4) 控制耦合 。一个模块通过接口向另一个模块传递一个控制信号,接受信号的模块根据信号值而进行适当的动作,这种耦合被称为控制耦合。
(5) 标记耦合 。若一个模块A通过接口向两个模块B和C传递一个公共参数,那么称模块B和C之间存在一个标记耦合。
(6) 数据耦合。模块之间通过参数来传递数据,那么被称为数据耦合。数据耦合是最低的一种耦合形式,系统中一般都存在这种类型的耦合,因为为了完成一些有意义的功能,往往需要将某些模块的输出数据作为另一些模块的输入数据。
(7) 非直接耦合 。两个模块之间没有直接关系,它们之间的联系完全是通过主模块的控制和调用来实现的。
总结:耦合是影响软件复杂程度和设计质量的一个重要因素,在设计上我们应采用以下原则:如果模块间必须存在耦合,就尽量使用数据耦合,少用控制耦合,限制公共耦合的范围,尽量避免使用内容耦合。
1.3使用工厂设计模式
interface IMessage{
public String getContent();
}
class NetMessage implements IMessage{
@Override
public String getContent() {
return "【网络消息】今天不用学习了 睡觉吧";
}
}
class Factory{ //工厂类
public static IMessage getInstance(String className){
if("netmessage".equalsIgnoreCase(className)){
return new NetMessage();
}
return null;
}
}
public class TestFactory { //主类
public static void main(String[] args) { //主方法
IMessage msg = Factory.getInstance("netmessage");
System.out.println(msg.getContent());
}
}
程序执行结果:
【网络消息】今天不用学习了 睡觉吧
此时的客户端不再关注具体的接口子类对象是如何创建的,此时所有与子类有关的定义全部交由Factory工厂类来完成,客户端不再关注子类,这样就避免了客户端与接口子类之间的耦合问题。
以上只是最简单的工厂设计模式,但是这样的设计本身是存在缺陷的,因为当前所使用的工厂类如果在面对接口之类增加的时候也需要进行修改。
interface IMessage{
public String getContent();
}
class NetMessage implements IMessage{
@Override
public String getContent() {
return "【网络消息】今天不用学习了 睡觉吧";
}
}
class NewspaperMessage implements IMessage{
@Override
public String getContent() {
return "【报纸消息】刚才的网络消息是假的 学习不能停";
}
}
class Factory{ //工厂类
public static IMessage getInstance(String className){
if("netmessage".equalsIgnoreCase(className)){
return new NetMessage();
}
if("newspapermessage".equalsIgnoreCase(className)){
return new NewspaperMessage();
}
return null;
}
}
public class TestFactory { //主类
public static void main(String[] args) { //主方法
IMessage msg = Factory.getInstance("netmessage");
IMessage msg1 = Factory.getInstance("newspapermessage");
System.out.println(msg.getContent());
System.out.println(msg1.getContent());
}
}
程序执行结果:
【网络消息】今天不用学习了 睡觉吧
【报纸消息】刚才的网络消息是假的 学习不能停
此时工厂类随着子类的增加也必须改动 这并不是我们想要的
所以,如果想要彻底编写一个完善的工厂设计模式并不容易(这里面所包括的问题不仅仅是一个对象实例化问题,还包含对象管理,对象个数控制等等一系列问题)。
现在这篇文章只是通过一个最简单的模型来介绍工厂设计模式
在以后的不断学习中 再慢慢完善工厂设计模式。