网站的建设需要虚拟机吗,网站开发和网络工程师,福州公司建站,沈阳seo整站优化目录 一、简介1.1、接口定义1.2、调用 二、简单工厂模式2.1、解析工厂2.2、调用 三、工厂方法模式3.1、解析器接口定义3.2、解析工厂接口定义3.3、解析器工厂的工厂3.4、调用 四、抽象工厂模式4.1、内容解析器4.2、工厂类 三、优点与缺点 一、简介 工厂模式我将它分为三类… 目录 一、简介1.1、接口定义1.2、调用 二、简单工厂模式2.1、解析工厂2.2、调用 三、工厂方法模式3.1、解析器接口定义3.2、解析工厂接口定义3.3、解析器工厂的工厂3.4、调用 四、抽象工厂模式4.1、内容解析器4.2、工厂类 三、优点与缺点 一、简介 工厂模式我将它分为三类
简单工厂模式工厂方法模式抽象工厂模式 抽象工厂用得比较少我主要讲解下简单工厂模式和工厂方法模式假设我们根据配置文件的扩展名xml、yml、properties获取到不同的解析器XmlRuleConfigParser、YmlRuleConfigParser、PropertiesRuleConfigParser从而解析得到结果RuleConfig相信大家很简单的就写出了如下的代码
1.1、接口定义
public class RuleConfig {// 属性忽略
}public interface IRuleConfigParser {RuleConfig parse(String configText);
}public class XmlRuleConfigParser implements IRuleConfigParser {Overridepublic RuleConfig parse(String configText) {// 实现 XML 配置解析逻辑// 返回 RuleConfig 对象return new RuleConfig(); // 假设这里返回 RuleConfig 对象}
}public class YmlRuleConfigParser implements IRuleConfigParser {Overridepublic RuleConfig parse(String configText) {// 实现 YML 配置解析逻辑// 返回 RuleConfig 对象return new RuleConfig(); // 假设这里返回 RuleConfig 对象}
}public class PropertiesRuleConfigParser implements IRuleConfigParser {Overridepublic RuleConfig parse(String configText) {// 实现 Properties 配置解析逻辑// 返回 RuleConfig 对象return new RuleConfig(); // 假设这里返回 RuleConfig 对象}
}这里我们定义了一个解析器接口并且有三个解析都实现了该接口最终返回解析的结果。
1.2、调用
RuleConfigSource.java
public class RuleConfigSource {public RuleConfig loadConfig() {String configFilePath config.xml; // 假设配置文件路径String fileType getFileExtension(configFilePath); // 获取文件类型xml、yml、propertiesIRuleConfigParser parsernull;if (xml.equalsIgnoreCase(fileType)) {parser new XmlRuleConfigParser();} else if (yml.equalsIgnoreCase(fileType)) {parser new YmlRuleConfigParser();} else if (properties.equalsIgnoreCase(fileType)) {parser new PropertiesRuleConfigParser();}else {throw new IllegalArgumentException(Unknown file type: fileType);}// 解析配置文件RuleConfig ruleConfig parser.parse(configFilePath);// 返回解析后的 ruleConfig 对象return ruleConfig;}private String getFileExtension(String filePath) {if (filePath null || filePath.isEmpty()) {throw new IllegalArgumentException(File path is invalid);}int lastDotIndex filePath.lastIndexOf(.);if (lastDotIndex -1) {throw new IllegalArgumentException(File path does not contain a valid file extension);}return filePath.substring(lastDotIndex 1);}}我敢肯定的说绝大部分的小伙伴都是这么写的完全没毛病我以前也是这么写过不过我们今天说的是设计模式讲的是一个接近规范的方法而不是说代码可读性什么的。那就看看使用简单工厂模式是什么样的。
二、简单工厂模式 简单工厂模式Simple Factory Pattern是通过一个工厂类来创建不同类型的对象客户端通过工厂类的静态方法来获取所需的对象。在简单工厂模式中工厂类负责所有产品的创建。 首先是要理解为啥要改一切的依据都是从七大设计原则来探讨设计模式如果不结合实际业务确实有点不合适。在我们使用的RuleConfigSource并没有满足单一职责原则它并不需要知道怎么去获取解析器的详细信息也不符合开闭原则所有的逻辑都在这里修改不便。在接口定义不变的前提下改造如下
2.1、解析工厂
RuleConfigParserFactory.java
import java.util.HashMap;
import java.util.Map;public class RuleConfigParserFactory {private static final MapString, RuleConfigParser PARSER_MAP new HashMap();static {PARSER_MAP.put(xml, new XmlRuleConfigParser());PARSER_MAP.put(yml, new YmlRuleConfigParser());PARSER_MAP.put(properties, new PropertiesRuleConfigParser());}public static RuleConfigParser createParser(String fileExtension) {if (PARSER_MAP.containsKey(fileExtension)) {return PARSER_MAP.get(fileExtension);}return null;}}2.2、调用
public class RuleConfigSource {public RuleConfig loadConfig() {String configFilePath config.xml; // 假设配置文件路径// 获取文件后缀可以放到工具类String fileExtension getFileExtension(configFilePath);// 获取解析器RuleConfigParser parser RuleConfigParserFactory.createParser(fileExtension);if (parsernull){throw new IllegalArgumentException(Unknown file type: fileExtension);}// 解析配置文件RuleConfig ruleConfig parser.parse(configFilePath);// 返回解析后的 ruleConfig 对象return ruleConfig;}private static String getFileExtension(String filePath) {// 从文件路径中提取文件类型后缀if (filePath null || filePath.isEmpty()) {throw new IllegalArgumentException(File path is invalid);}int lastDotIndex filePath.lastIndexOf(.);if (lastDotIndex -1) {throw new IllegalArgumentException(File path does not contain a valid file extension);}return filePath.substring(lastDotIndex 1);}}这里的RuleConfigSource就不会涉及到具体解析器的构建和解析并且增加一个也与它没关系只需要改动RuleConfigParserFactory有些人说这也违反了开闭原则实际上如果不是很频繁的添加新的解析器只是偶尔修改RuleConfigParserFactory的代码即便不符合开闭原则也是可以被接受的。并且这里通过静态代码块节省了内存和对象创建的开销。
三、工厂方法模式 工厂方法模式Factory Method Pattern则是将对象的创建推迟到具体工厂类中定义一个抽象的工厂接口每个具体工厂类都实现这个接口负责创建特定的对象。每个具体工厂类只负责创建单一类型的对象。 还是用之前的示例来改造成工厂方法模式理论上工厂方法模式比简单工厂模式更加符合开闭原则。
3.1、解析器接口定义
public class RuleConfig {// 属性忽略
}public interface IRuleConfigParser {RuleConfig parse(String configText);
}public class XmlRuleConfigParser implements IRuleConfigParser {Overridepublic RuleConfig parse(String configText) {// 实现 XML 配置解析逻辑// 返回 RuleConfig 对象return new RuleConfig(); // 假设这里返回 RuleConfig 对象}
}public class YmlRuleConfigParser implements IRuleConfigParser {Overridepublic RuleConfig parse(String configText) {// 实现 YML 配置解析逻辑// 返回 RuleConfig 对象return new RuleConfig(); // 假设这里返回 RuleConfig 对象}
}public class PropertiesRuleConfigParser implements IRuleConfigParser {Overridepublic RuleConfig parse(String configText) {// 实现 Properties 配置解析逻辑// 返回 RuleConfig 对象return new RuleConfig(); // 假设这里返回 RuleConfig 对象}
}3.2、解析工厂接口定义 我们需要给每个解析器都增加一个工厂类。
public interface IRuleConfigParserFactory {IRuleConfigParser createParser();
}public class XmlRuleConfigParserFactory implements IRuleConfigParserFactory {Overridepublic IRuleConfigParser createParser() {return new XmlRuleConfigParser();}
}public class YmlRuleConfigParserFactory implements IRuleConfigParserFactory {Overridepublic IRuleConfigParser createParser() {return new YmlRuleConfigParser();}
}public class PropertiesRuleConfigParserFactory implements IRuleConfigParserFactory {Overridepublic IRuleConfigParser createParser() {return new PropertiesRuleConfigParser();}
}3.3、解析器工厂的工厂 然后管理这些工程类也就是建立一个工厂的工厂。
import java.util.HashMap;
import java.util.Map;public class RuleConfigParserFactoryMap {private static final MapString, IRuleConfigParserFactory PARSER_MAP new HashMap();static {PARSER_MAP.put(xml, new XmlRuleConfigParserFactory());PARSER_MAP.put(yml, new YmlRuleConfigParserFactory());PARSER_MAP.put(properties, new PropertiesRuleConfigParserFactory());}public static IRuleConfigParserFactory getParserFactory(String fileExtension) {// 获取解析工厂if (PARSER_MAP.containsKey(fileExtension)) {return PARSER_MAP.get(fileExtension);}return null;}}3.4、调用
public class RuleConfigSource {public RuleConfig loadConfig() {String configFilePath config.xml; // 假设配置文件路径String fileExtension getFileExtension(configFilePath);// 获取文件类型xml、yml、properties// 获取解析器IRuleConfigParserFactory parserFactory RuleConfigParserFactoryMap.getParserFactory(fileExtension);if (parserFactory null) {throw new IllegalArgumentException(未找到解析工厂);}IRuleConfigParser parser parserFactory.createParser();// 返回解析后的 ruleConfig 对象return parser.parse(configFilePath);}private static String getFileExtension(String filePath) {// 从文件路径中提取文件类型后缀// 这里假设实现获取文件类型的逻辑if (filePath null || filePath.isEmpty()) {throw new IllegalArgumentException(File path is invalid);}int lastDotIndex filePath.lastIndexOf(.);if (lastDotIndex -1) {throw new IllegalArgumentException(File path does not contain a valid file extension);}return filePath.substring(lastDotIndex 1);}}当我们需要新的解析器时只需要定义新的解析器对应的类和工厂类并且缓存起来这样代码也改得很少基本符合开闭原则。但是和简单工厂方法相比实现上差不多反而增加了代码的复杂度尤其是在工厂类的实现非常简单的情况下有点过渡设计了这时使用简单工厂方法就可以了如果每个解析对象的创建逻辑都比较的复杂需要组合其他的组件那么可以考虑工厂方法模式。
四、抽象工厂模式 抽象工厂模式Abstract Factory Pattern用于创建一组相关或相互依赖的对象它通过提供一个创建一系列相关对象的接口可以创建不同类型的对象组。 工厂方法模式已经复杂起来了抽象工厂模式很大程度是在这个基础上演变的。比如我们是之前是按照后缀名解析的假设我们同时需要按照内容格式来解析呢那工程类就变成6个了这个时候就可以使用抽象工厂模式了。
4.1、内容解析器 假设我们增加解析器 内容解析器
public interface IContentConfigParser {RuleConfig parse(String configText);
}public class XmlContentConfigParser implements IContentConfigParser {Overridepublic RuleConfig parse(String configText) {return new RuleConfig();}
}public class YmlContentConfigParser implements IContentConfigParser {Overridepublic RuleConfig parse(String configText) {return new RuleConfig();}
}public class PropertiesContentConfigParser implements IContentConfigParser {Overridepublic RuleConfig parse(String configText) {return new RuleConfig();}
}4.2、工厂类
public interface IConfigParserFactory {IRuleConfigParser createRuleParser();IContentConfigParser createContentParser();
}public class XmlConfigParserFactory implements IConfigParserFactory {Overridepublic IRuleConfigParser createRuleParser() {return new XmlRuleConfigParser();}Overridepublic IContentConfigParser createContentParser() {return new XmlContentConfigParser();}
}public class YmlConfigParserFactory implements IConfigParserFactory {Overridepublic IRuleConfigParser createRuleParser() {return new YmlRuleConfigParser();}Overridepublic IContentConfigParser createContentParser() {return new YmlContentConfigParser();}
}public class PropertiesConfigParserFactory implements IConfigParserFactory {Overridepublic IRuleConfigParser createRuleParser() {return new PropertiesRuleConfigParser();}Overridepublic IContentConfigParser createContentParser() {return new PropertiesContentConfigParser();}
}从而达到减少工厂类的个数不过实际中抽象工厂模式用得比较少。可能很多小伙伴还是觉得这个工厂模式有问题比如本文中的工厂或者工厂的工厂缓存可以使用配置文件反射去掉完全适合开闭原则每个设计模式都有自己的特色和缺点就看是否被接受。遵循一些原则的同时需要考虑代码的复杂度清晰度。
三、优点与缺点
简单工厂模式
优点
实现简单易于理解和使用。将对象的创建过程封装在工厂类中客户端无需了解对象创建的具体逻辑。
缺点
工厂类集中了所有对象的创建逻辑如果需要添加新产品可能需要修改工厂类的逻辑不符合开闭原则。不符合单一职责原则因为工厂类既要负责对象的创建又要负责选择创建哪个对象。
工厂方法模式
优点 每个具体工厂只负责创建特定的对象符合单一职责原则。 可以通过扩展具体工厂类来添加新产品无需修改现有代码符合开闭原则。 缺点 增加了系统中类的个数增加了系统的复杂度。 客户端需要知道所使用的具体工厂类导致与具体工厂类耦合。
抽象工厂模式
优点
具有工厂方法模式的所有优点同时能够创建一组相关的产品对象形成产品族。客户端与具体产品的实现解耦更符合依赖倒置原则。
缺点
添加新产品族比较复杂需要修改抽象工厂接口及其所有实现类。增加系统的抽象性和理解难度需要同时理解多个抽象类和接口。 根据实际需求选择适合的工厂模式是非常重要的简单工厂适用于对象较少且创建逻辑不复杂的情况工厂方法适用于需要创建多种类型对象的情况而抽象工厂适用于创建一组相关对象的场景但要考虑到增加产品的复杂度。