设计模式(Design Pattern)是一套被辰复使用的、多数人知時的人经过分类编目的、代码
设计经验的总结,使用设计模式题为了可重用代码,让代码更容易被他人理解并目提高代码所可靠性。设计模式是一种用于对软件系统中不断重现的设计问题的解决方案进行文档化的技术,也是一种共享专家设计经验的技术
GOF对设计模式的定义如下:
设计模式是在特定环境下为解决某一通用软件设计问题提供的一套定制的解决方案,改方案描述了对象和类之间的相互作用
在软件开发中使用面向对象设计原则可以提高软件的可维护性和可复用性,以便设计出兼具良好的可维护性和可复用性的软件系统,实现可维护性复用的目标
创建型:工厂模式,抽象工厂模式,方法模式,建造者模式,原型模式、单例模式
行为型:职责链模式,迭代器模式,中介者模式,备忘录模式,观察者模式,策略模式,状态模式,模板方法模式,访问者模式
结构型:适配器模式,桥接模式,组合模式,装饰模式,外观模式,享元模式,代理模式
根据作用范围来分
根据模式是主要用于类上还是主要用于对象上来分,这种方式可分为类模式和对象模式两种。
范围\目的 | 创建型模式 | 结构型模式 | 行为型模式 |
---|---|---|---|
类模式 | 工厂方法 | (类)适配器 | 模板方法、解释器 |
对象模式 | 单例 原型 抽象工厂 建造者 |
代理 (对象)适配器 桥接 装饰 外观 享元 组合 |
策略 命令 职责链 状态 观察者 中介者 迭代器 访问者 备忘录 |
创建型模式藐视如何将对象的创建和使用分离,让用户在使用对象时无须关心对象的创建细节,从而降低系统的耦合度,让设计方案更易于修改和扩展
简单工厂模式时最简单的设计模式之一,它虽然不属于GOF的23中设计模式,但是应用也比较频繁,同时也是学习其他创建型模式的基础
举个实例:一个水果农场,当用户需要某一种水果时,该农场能后根据用户多提供的水果名称返回该水果,在此,水果农场被称为工厂(Factory),而生成的水果被称为产品(Product),水果名称则为参数,工厂可以根据参数的不同返回不同的产品,这就是简单工厂模式的动机。
简单工厂模式的设计思想和实现过程都比较简单,其基本实现流程如下:
首先将需要创建的各种不同产品对象的相关代码封装到不同的类中,这些类称为具体产品类,而将它们公共的代码进行抽象和提取后封装在一个抽象产品类中,每一个具体产品类都是抽象产品类的子类;然后提供一个工厂类用于创建各种产品,子啊工厂类中提供一个创建产品的工厂方法,该方法可以根据所传入的参数不同创建不同的具体产品对象;客户端只需调用工厂类的工厂方法并传入相对应的参数即可得到一个产品对象
简单工厂模式的定义如下:
定义一个工厂类,可以根据参数的不同范围不同类的实例,被创建的实例通常都具有共同的父类。
3个角色
(1)Factory(工厂角色)
(2)Product(抽象产品角色)
(3)ConcreteProduct(具体产品角色)
简单工厂模式结构图
抽象产品 类代码
public abstract class Product{
//所有产品类的公共业务方法
public void methodSame(){
//公共方法的实现
}
//声明抽象业务方法
public abstract void methodDiff();
}
具体产品类的代码
public class ConcreteProduct extends Product {
//实现业务方法
public void methodDiff(){
//业务方法的实现
}
}
典型的 工厂类
public class Factory{
//静态工厂方法
public static Product getProduct(String arg){
Product product = null;
if(arg.equalsIgnoreCase("A")){
product = new ConcreteProductA();
//初始化设置product
}else if (arg.equalsIgnoreCase("B")){
product = new ConcreteProductB();
//初始化设置product
}
return product;
}
}
客户端代码
public class Client{
public static void main(String arg[]){
Product product;
product = Factory.getProduct("A");//通过工厂类创建产品对象
product.methodSame();
product.methodDiff();
}
}
为了不违反开闭原则,我们可以将静态工厂方法的参数存储到XML格式的配置文件中,类如
A
再通过一个工具类XMLUtil来读取配置文件中的字符串参数,代码如下:
package designpatterns.simplefactory;
import javax.xml.parsers.*;
import org.w3c.dom.*;
import org.xml.sax.SAXException;
import java.io.*;
public class XMLUtil{
//该方法用于从xml配置文件中提取类型,并返回类型名
public static String getChartType(){
try{
//创建文档对象
DocumentBuilderFatory dFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = dFactory.newDocumentBuilder();
Document doc;
doc=builder.parse(new File("src//designpatterns//simplefactory//comfig.xml"));
//获取包含图标类型的文本结点
NodeList nl = doc.getElementByTagName("A");
Node classNode = nl.item(0).getFirstChild();
String chartType = classNode.getNodeValue().trim();
return chartType;
}catch(Exception e){
e.printStackTrace();
return null;
}
}
}
引入工具类以后,客户端代码修改一下:
public class Client{
public static void main(String arg[]){
Product product;
String type = XMLUtil.getChartType();//读取配置文件中的参数
product = Factory.getProduct(type);//通过工厂类创建产品对象
product.methodSame();
product.methodDiff();
}
}
只需要修改xml配置文件,无需修改任何源代码,符合开闭原则。
优点:(1)简单工厂模式实现了对象创建和使用的分离
(2)客户端无需知道所创建的具体产品类的类名
(3)通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统地灵活性
缺点:(1)由于工厂类集中了所有产品的创建逻辑,职责过重,一旦不能正常工作,整个系统都要受到影响
(2)使用简单工厂模式势必会增加系统中类的个数(引入新的工厂类),增加了系统的复杂度和理解难度
(3)系统扩展困难
(4)简单工厂模式由于使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构
(1)工厂类负责创建的对象比较少,由于创建的对象比较少,不会造成工厂方法中的业务逻辑太过复杂
(2)客户端只知道传入工厂类的参数,对于如何创建对象并不关心
使用简单工厂模式模拟女娲(Nvwa)造人(Person),如果向造人的工厂方法传入参数“M”。则返回一个男人(Man)对象,如果传入参数“W”,则返回一个女人(Woman)对象,绘制相应的类图并且使用Java语言模拟实现该场景。现需要增加一个新的机器人(Robot)类,如果传入参数“R”,则返回一个机器人对象,对代码进行修改并注意“女娲”类的变化。
1)没有添加之前
2)添加之后
代码
//抽象产品类
//Person接口
public interface Person {
void create();
}
//具体产品类
//Man(男人)类
public class Man implements Person{
public Man() {
}
@Override
public void create() {
System.out.println("创建男人中-----");
}
}
//具体产品类
//Woman(女人)类
public class Woman implements Person{
public Woman() {
}
@Override
public void create() {
System.out.println("创建女人中---------");
}
}
//具体产品类
//Robot(机器人)类
public class Robot implements Person{
public Robot() {
}
@Override
public void create() {
System.out.println("创建机器人中-------");
}
}
//工厂类
//Nvwa(女娲)类
public class Nvwa {
public static Person getPerson(String person) throws Exception {
if (person.equalsIgnoreCase("M")){
return new Man();
}else if (person.equalsIgnoreCase("W")){
return new Woman();
}else if (person.equalsIgnoreCase("R")){
return new Robot();
}else {
throw new Exception("创建错误!!!");
}
}
}
//客户端测试类
public class Client{
public static void main(String[] args) throws Exception {
Person person = Nvwa.getPerson("W");
person.create();
}
}