23种设计模式,共分为三大类:创建型模式、结构型模式、行为型模式。
- 创建型模式:关注对象的创建过程。
- 包含:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
- 结构性模式:关注对象和类的组织。
- 包含:适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式。
- 行为型模式:关注系统中对象之间的相互交互,研究系统在运行时对象之间的相互通信和协作,进一步明确对象的职责。
- 包含:模板方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、策略模式、职责链模式、访问者模式。
简单工厂模式
一、概念
简单工厂模式也叫做静态工厂。简单工厂主要是根据不同的参数返回不同类的实例。
二、作用
定义一个类专门负责创建其他类的实例,“其他类”有一个共同的父类。
三、举例
使用面向对象实现两个数的基本运算(加、减、乘、除)
四、UML图
解释:
运算类和简单工厂类之间是关联关系,简单工厂类种引用了运算类的对象。
加法类、减法类、乘法类和除法类分别继承了运算类,实现了运算类种的抽象方法,用于实现各自的功能。
五、实现代码
5.1、运算类:
package com.example.factory.simpleFactory;
/**
* 将其他类的公共属性和方法提取出来,封装成抽象类
*/
public abstract class Operation {
private double numberA=0;
private double numberB=0;
public double getNumberA() {
return numberA;
}
public void setNumberA(double numberA) {
this.numberA = numberA;
}
public double getNumberB() {
return numberB;
}
public void setNumberB(double numberB) {
this.numberB = numberB;
}
public abstract double getResult();
}
5.2、加减乘除类
package com.example.factory.simpleFactory;
public class OperationAdd extends Operation {
@Override
public double getResult() {
return getNumberA()+getNumberB();
}
}
package com.example.factory.simpleFactory;
public class OperationSub extends Operation {
@Override
public double getResult() {
return getNumberA()-getNumberB();
}
}
package com.example.factory.simpleFactory;
public class OperationMul extends Operation {
@Override
public double getResult() {
return getNumberA()*getNumberB();
}
}
package com.example.factory.simpleFactory;
public class OperationDiv extends Operation {
@Override
public double getResult() {
return getNumberA()/getNumberB();
}
}
5.3、简单工厂类
package com.example.factory.simpleFactory;
/**
* 简单工厂类,用于创建其他类的实例
*/
public class OperationFactory {
public static Operation createOperation(String operate){
Operation operation = null;
switch (operate){
case "+":
operation = new OperationAdd();
break;
case "-":
operation = new OperationSub();
break;
case "*":
operation = new OperationMul();
break;
case "/":
operation = new OperationDiv();
break;
}
return operation;
}
}
六、客户端测试
package com.example.factory;
import com.example.factory.simpleFactory.Operation;
import com.example.factory.simpleFactory.OperationFactory;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
class FactoryApplicationTests {
@Test
public void testSimpleFactory(){
double result = 0;
//使用了多态:父类引用指向了子类对象
Operation operation_add = OperationFactory.createOperation("+");
//使用了封装,通过方法为私有的属性进行赋值
operation_add.setNumberA(2.2);
operation_add.setNumberB(3.3);
//调用子类的方法,实现两数相加
result = operation_add.getResult();
System.out.println("两数相加:"+result);
Operation operation_sub = OperationFactory.createOperation("-");
operation_sub.setNumberA(2.2);
operation_sub.setNumberB(3.3);
result = operation_sub.getResult();
System.out.println("两数相减:"+result);
Operation operation_mul = OperationFactory.createOperation("*");
operation_mul.setNumberA(2.2);
operation_mul.setNumberB(3.3);
result = operation_mul.getResult();
System.out.println("两数相乘:"+result);
Operation operation_div = OperationFactory.createOperation("/");
operation_div.setNumberA(2.2);
operation_div.setNumberB(3.3);
result = operation_div.getResult();
System.out.println("两数相除:"+result);
}
}
七、修改、扩展
如果需要修改/增加一个新的算术运算。需要修改的代码如下:
修改的话,就是修改对应的运算子类。
添加的话,则需要我们添加一个运算的子类,并在简单工厂类中添加对应的case语句。
八、总结
开放-封闭原则:软件实体(类、模块、函数等等)可以扩展,但是不可以修改。就是对扩展是开放的,对修改时关闭的。
使用简单工厂模式,在扩展功能的时候违背了开放封闭原则。因为修改了工厂类中的函数。那该怎么处理呢?
答:可以进一步使用工厂方法模式。
工厂方法模式
一、概念
工厂方法模式中,在客户端不会暴露创建对象的逻辑,是通过使用一个共同的接口来指向新创建的对象。
二、作用
定义一个用于创建对象的接口,让子类决定实例化哪一个类,使一个类的实例化延迟到其子类。
三、工厂方法模式结构图
Product接口:定义工厂方法锁创建对象的接口
Creator接口:工厂接口,声明工厂方法,该方法返回一个Product类型的对象
ConcreteProduct实现类:具体的产品,实现了Product接口
ConcreteCreator实现类:实现工厂方法返回一个ConcreteProduct实例
四、举例
使用过程方法模式实现两个数的基本运算(加、减、乘、除)
五、实例UML
六、实现代码
6.1、运算类
package com.example.factory.factoryPattern;
/**
* 将其他类的公共属性和方法提取出来,封装成抽象类
*/
public abstract class Operation {
private double numberA=0;
private double numberB=0;
public double getNumberA() {
return numberA;
}
public void setNumberA(double numberA) {
this.numberA = numberA;
}
public double getNumberB() {
return numberB;
}
public void setNumberB(double numberB) {
this.numberB = numberB;
}
public abstract double getResult();
}
6.2、运算类的子类(加、减、乘、除)
package com.example.factory.factoryPattern;
public class OperationAdd extends Operation {
@Override
public double getResult() {
return getNumberA()+getNumberB();
}
}
package com.example.factory.factoryPattern;
public class OperationSub extends Operation {
@Override
public double getResult() {
return getNumberA()-getNumberB();
}
}
package com.example.factory.factoryPattern;
public class OperationMul extends Operation {
@Override
public double getResult() {
return getNumberA()*getNumberB();
}
}
package com.example.factory.factoryPattern;
public class OperationDiv extends Operation {
@Override
public double getResult() {
return getNumberA()-getNumberB();
}
}
6.3、抽象工厂接口
package com.example.factory.factoryPattern;
public interface IFactory {
Operation CreateOperation();
}
6.4、工厂具体的实现类(加法工厂、减法工厂、乘法工厂、除法工厂)
package com.example.factory.factoryPattern;
public class AddFactory implements IFactory {
@Override
public Operation CreateOperation() {
return new OperationAdd();
}
}
package com.example.factory.factoryPattern;
public class SubFactory implements IFactory {
@Override
public Operation CreateOperation() {
return new OperationSub();
}
}
package com.example.factory.factoryPattern;
public class MulFactory implements IFactory {
@Override
public Operation CreateOperation() {
return new OperationMul();
}
}
package com.example.factory.factoryPattern;
public class DivFactory implements IFactory {
@Override
public Operation CreateOperation() {
return new OperationDiv();
}
}
七、客户端测试
package com.example.factory;
import com.example.factory.factoryPattern.*;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
//import com.example.factory.simpleFactory.Operation;
@RunWith(SpringRunner.class)
@SpringBootTest
class FactoryApplicationTests {
@Test
public void testFactoryPattern(){
double result = 0;
IFactory factory = null;
//使用了多态:父类引用指向了子类对象,就创建一个加法工厂
factory = new AddFactory();
//使用加法工厂创建了一个加法的实例
Operation operationAdd = factory.CreateOperation();
//使用加法实例调用加法的实例方法
operationAdd.setNumberA(4);
operationAdd.setNumberB(2);
result = operationAdd.getResult();
System.out.println("使用工厂模式——两数相加:"+result);
//使用了多态:父类引用指向了子类对象,就创建一个减法工厂
factory = new SubFactory();
//使用加法工厂创建了一个减法的实例
Operation operationSub = factory.CreateOperation();
//使用减法实例调用减法的实例方法
operationSub.setNumberA(4);
operationSub.setNumberB(2);
result = operationSub.getResult();
System.out.println("使用工厂模式——两数相减:"+result);
//使用了多态:父类引用指向了子类对象,就创建一个乘法工厂
factory = new MulFactory();
//使用加法工厂创建了一个乘法的实例
Operation operationMul = factory.CreateOperation();
//使用乘法实例调用乘法的实例方法
operationMul.setNumberA(4);
operationMul.setNumberB(2);
result = operationMul.getResult();
System.out.println("使用工厂模式——两数相乘:"+result);
//使用了多态:父类引用指向了子类对象,就创建一个除法工厂
factory = new DivFactory();
//使用加法工厂创建了一个除法的实例
Operation operationDiv = factory.CreateOperation();
//使用除法实例调用除法的实例方法
operationDiv.setNumberA(4);
operationDiv.setNumberB(2);
result = operationDiv.getResult();
System.out.println("使用工厂模式——两数相除:"+result);
}
}
八、修改、扩展
如果需要进行修改/扩展算术运算,需要修改的代码如下:
修改的话:修改对应的运算子类
扩展的话,需要添加一个运算子类、一个运算工厂的实现类。
九、总结
使用工厂方式模式实现,添加一个功能,只是扩展上的变化,完全符合【开放——封闭】原则。
但是,工厂方法模式实现时,客户端要决定实例化哪一个工厂来实现运算类,选择判断的问题还是存在,也就是说,工厂方法把简单工厂的内部逻辑判断移到了客户端代码上进行。添加一个功能,简单工厂模式是修改工厂类,工厂方法模式是修改客户端。
抽象工厂模式
一、概念
抽象工厂模式就是提供一个创建一系列相关或相互依赖的接口,而无需指定它们具体的类。
二、作用
解决系统中有多个产品族,而系统只使用其中某一族的产品。(一个产品族里有多个产品)
三、抽象工厂模式结构图
AbstractProductA、AbstractProductB:抽象产品。
ProductA_1、ProductA_2、ProductB_1、ProductB_2:抽象产品的具体实现。
AbstractFactory:抽象工厂接口,应该包含所有产品创建的抽象方法。
ConcreteFactory_1、ConcreteFactory_2:具体的工厂,创建具有产品实现的工厂。
四、举例
某个系统需要在不同数据库间进行切换,同一种数据库中有多张数据表需要进行操作。
可以把每种数据库看作是一个工厂,数据库中的数据表看作是工厂里产品。
五、实例UML
六、实例代码
6.1、抽象产品接口
package com.example.factory.abstractFactory;
public interface ITeacher {
void saveTeacher();
void getTeacher();
}
package com.example.factory.abstractFactory;
public interface IStudent {
void saveStudent();
void getStudent();
}
6.2、具体产品的实现
ITeacher:
package com.example.factory.abstractFactory;
public class OracleTeacher implements ITeacher {
@Override
public void saveTeacher() {
System.out.println("使用Oracle数据库——保存teacher信息");
}
@Override
public void getTeacher() {
System.out.println("使用Oracle数据库——获取teacher信息");
}
}
package com.example.factory.abstractFactory;
public class MySqlTeacher implements ITeacher {
@Override
public void saveTeacher() {
System.out.println("使用MySql数据库——保存teacher信息");
}
@Override
public void getTeacher() {
System.out.println("使用MySql数据库——获取teacher信息");
}
}
IStudent:
package com.example.factory.abstractFactory;
public class OracleStudent implements IStudent {
@Override
public void saveStudent() {
System.out.println("使用Oracle数据库——保存student信息");
}
@Override
public void getStudent() {
System.out.println("使用Oracle数据库——获取student信息");
}
}
package com.example.factory.abstractFactory;
public class MySqlStudent implements IStudent {
@Override
public void saveStudent() {
System.out.println("使用MySql数据库——保存student信息");
}
@Override
public void getStudent() {
System.out.println("使用MySql数据库——获取student信息");
}
}
6.3、抽象工厂
package com.example.factory.abstractFactory;
public interface IDBFactory {
IStudent createStudent();
ITeacher createTeacher();
}
6.4、具体工厂
package com.example.factory.abstractFactory;
public class OracleFactory implements IDBFactory {
@Override
public IStudent createStudent() {
return new OracleStudent();
}
@Override
public ITeacher createTeacher() {
return new OracleTeacher();
}
}
package com.example.factory.abstractFactory;
public class MySqlFactory implements IDBFactory {
@Override
public IStudent createStudent() {
return new MySqlStudent();
}
@Override
public ITeacher createTeacher() {
return new MySqlTeacher();
}
}
七、客户端测试
package com.example.factory;
import com.example.factory.abstractFactory.*;
import com.example.factory.factoryPattern.*;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
//import com.example.factory.simpleFactory.Operation;
@RunWith(SpringRunner.class)
@SpringBootTest
class FactoryApplicationTests {
@Test
public void testAbstractFactoryPattern(){
IDBFactory factory;
//如果需要切换数据库,只需要在new一个数据库工厂
//factory = new MySqlFactory();
factory = new OracleFactory();
ITeacher it = factory.createTeacher();
it.saveTeacher();
it.getTeacher();
IStudent is = factory.createStudent();
is.saveStudent();
is.getStudent();
}
}
八、扩展
如果需要新增一种数据库的访问或者是新增一张数据表,该如何进行扩展?
新增数据库SqlServer:首先需要在每个产品类下添加一个实现类,如SqlServerTeacher、SqlServerStudent;其次需要新增一个具体工厂的实现类SqlServerFactory,用来创建具体产品实例,如SqlServerTeacher实例和SqlServerStudent实例。
新增一张数据表School:首先需要添加School产品的接口及接口的实现类MySqlSchool、OracleSchool;其次需要在接口工厂中添加创建School对象的方法,并在每个实现类中实现创建School对象的方法。
工厂方法模式和抽象工厂模式的区别?
工厂方法模式:
- 一个抽象产品类,可以派生出多个具体产品类。
- 一个抽象工厂类,可以派生出多个具体过程类。
- 每个具体工厂类只能创建一个具体产品类的实例。
抽象工厂模式:
- 多个抽象产品类,每个抽象产品类可以派生出多个具体产品类。
- 一个抽象工厂类,可以派生出多个具体工厂类。
- 每个具体工厂类可以创建多个具体产品类的实例。
主要区别:
- 工厂方法模式只有一个抽象产品类,而抽象工厂模式有多个抽象产品类。
- 工厂方法模式的具体工厂类只能创建一个具体产品类的实例,而抽象工厂模式可以创建多个具体产品类的实例。
参考:《大话设计模式》