1.1 工厂模式
工厂模式一般分为简单工厂、工厂方法、抽象工厂,那么什么是简单工厂模式?工厂方法?抽象工厂模式?先看例子,再去看概念和UML图。
举例:
假设现在有一个项目要进行文件解析,需要根据文件的类型,去使用不同的文件解析器,比如json类型的文件需要用Json解析器,xml类型文件使用xml解析器等。
定义:
-
首先定义一个解析器接口:
public interface ITypeParser{ void parse(String text); }
-
再定义具体的解析器类JsonTypeParser:
public class JsonTypeParser implements ITypeParser{ @Override public void parse(String text) { System.out.println("json解析器"); } }
-
再定义具体的解析器类XmlTypeParser:
public class XmlTypeParser implements ITypeParser{ @Override public void parse(String text) { System.out.println("xml解析器"); } }
1.1.1 不使用工厂模式
如果不使用工厂模式,我们一般的写法就是这样:
public class NonFactoryPattern {
public static void main(String[] args) {
/**
* 不使用工厂模式
*/
File file = new File("D:/com/..");
String fileName = file.getName();
String fileExtension = fileName.substring(fileName.lastIndexOf('.'));
ITypeParser iTypeParser = null;
if(fileExtension.equalsIgnoreCase("json")){
iTypeParser = new JsonTypeParser();
}else if(fileExtension.equalsIgnoreCase("xml")){
iTypeParser = new XmlTypeParser();
}
iTypeParser.parse("");
}
}
从上面的代码中可以看出一些问题:
(1)获取文件解析器对象的代码写在main方法中,即业务方法中,若在同一个业务里,需要多次用到文件解析器,那岂不是很多地方都有重复的代码块。
(2)获取解析器对象都在if-else中,如果要增加一个两个,那又得写出一个两个if-else,可见代码的扩展性不好。
那怎么解决上诉问题呢?
就是把获取解析器的代码写到一个类里,这样在业务方法中需要的时候直接调用这个类就好了。并且要扩展多个解析器的时候,只需要在那个类里修改就好了,不影响业务代码。-----> 简单工厂方法
1.1.2 简单工厂方法
使用简单工厂方法的代码如下:
业务代码:
//这个工厂只负责创建解析器对象
public class EasyFactory {
public ITypeParser getTypeParser(String fileExtension){
ITypeParser iTypeParser = null;
if(fileExtension.equalsIgnoreCase("json")){
iTypeParser = new JsonTypeParser();
}else if(fileExtension.equalsIgnoreCase("xml")){
iTypeParser = new XmlTypeParser();
}else if(fileExtension.equalsIgnoreCase("properties")){ //新增一个
// iTypeParser = new PropertiesTypeParser();
}
return iTypeParser;
}
}
从上面的代码我们可以看到一个问题:
每次增加一个解析器,是需要在这个工厂类里去添加一个if-else,即需要修改这个类中的代码,违反了开闭原则(对扩展开放,对修改关闭)。
那有什么办法解决呢?
可以给每个解析器都自己常见一个工厂,每个工厂都只负责创建自己的解析器,如XMLFactory只负责创建XmlTypeParser解析器。这就是工厂方法,即一个工厂下有多个具体工厂,每个工厂负责创建不同的产品。
1.1.3 工厂模式
将解析器的获取放在该解析器对应的具体的工厂中进一步解耦,这个时候如果需要扩展一个新的解析器,只需要再增加一个实现ITypeParserFactory的实现类就可以了,工厂方法模式比简单工厂模式更符合开闭原则。
-
定义一个工厂接口ITypeParserFactory :
public interface ITypeParserFactory { ITypeParser getParser(); }
-
具体的工厂JsonTypeParserFactory:
public class JsonTypeParserFactory implements ITypeParserFactory{ @Override public ITypeParser getParser() { return new JsonTypeParser(); } }
-
具体的工厂XmlTypeParserFactory:
public class XmlTypeParserFactory implements ITypeParserFactory{ @Override public ITypeParser getParser() { return new XmlTypeParser(); } }
-
业务代码:
public static void main(String[] args) { /** * 使用工厂方法 */ File file = new File("D:/com/.."); String fileName = file.getName(); String fileExtension = fileName.substring(fileName.lastIndexOf('.')); ITypeParserFactory iTypeParserFactory = null; if(fileExtension.equalsIgnoreCase("json")){ iTypeParserFactory = new JsonTypeParserFactory(); }else if(fileExtension.equalsIgnoreCase("xml")){ iTypeParserFactory = new XmlTypeParserFactory(); } iTypeParserFactory.getParser(); }
上面的业务代码看起来和没有使用工厂模式的代码差不多一样,但是仔细看,工厂方法中使用的是ITypeParserFactory,也就是使用的是工厂类,一般在业务代码中获取解析器的工厂对象是可以复用的,所以当使用更多的解析器时,可以直接使用iTypeParserFactory对象去获取解析器就可以了。 如果现在需要根据环境或其他因素选择解析器呢? 可以使用抽象工厂方法。
1.1.4 抽象工厂
简单工厂和工厂方法中,解析器只有一种分类方式,根据文件类型解析(json,xml等)。如果现在还需要根据文件环境来分类,如(开发环境,测试环境)或根据权限分类,如(管理员,普通用户)等。针对这种场景,如果使用工厂方法模式,需要针对每个parser编写工厂类,这样会产生大量的类,所以可以选择使用抽象工厂。
public interface IParserFactory {
ITypeParser getTypeParser();
IEnvParser getEnvParser();
}
在抽象工厂中创建一个根据环境选择解析器的方法,这样具体工厂实现抽象工厂时,就有相应的方法去提供了。
1.1.5 概念
-
简单工厂方法:
将业务代码中创建对象的复杂逻辑代码抽取到一个类中,但其不符合开闭原则,不常使用。
-
工厂模式:
(1)意图:定义一个创建对象(创建对象的工厂)的接口,让具体的工厂类去实现接口,将创建对象的过程延申到了子类。 (2)主要解决:接口选择问题。 (3)何时使用:计划在不同条件下使用不同的产品(创建不同的实例)。 (4)如何解决:让子类(具体的工厂)去实现工厂接口,返回一个抽象产品。 (5)优点: 扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。 屏蔽产品的具体实现,调用者只关心产品的接口。 (6)缺点: 每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。
-
抽象工厂:
(1)意图:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。(即可根据文件类型又需要根据环境选择不同的文件解析器)
(2)主要解决:接口选择问题。
(3)何时使用:系统的产品有多于一个的产品族,而系统只消费其中某一族的产品。(文件解析器即需要根据文件类型去选择,又需要根据环境去选择。又如所有的衣柜(具体工厂)都是衣柜类的(抽象工厂)某一个,而每一件成套的衣服又包括具体的上衣(某一具体产品),裤子(某一具体产品),这些具体的上衣其实也都是上衣(抽象产品),具体的裤子也都是裤子(另一个抽象产品)。)
(4)如何解决:在一个产品族里面,定义多个产品。
(5)优点:
当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。
(6)缺点:
产品族扩展非常困难,要增加一个系列的某一产品,既要在抽象的 Creator 里加代码,又要在具体的里面加代码。
1.1.6 工厂模式的好处
(1)封装变化:创建逻辑有可能变化,封装成工厂类之后,创建逻辑的变更对调用者透明。
(2)代码复用: 创建代码抽离到独立的工厂类之后可以复用。
(3)隔离复杂性:封装复杂的创建逻辑,调用者无需了解如何创建对象
(4)控制复杂度:将创建代码抽离出来,让原本的函数或类职责更单一,代码更简洁。
标签:解析器,String,代码,模式,工厂,案例,new,public
From: https://www.cnblogs.com/lxpblogs/p/16879079.html