简单工厂模式——>工厂方法模式——>抽象工厂模式

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对象的方法。

工厂方法模式和抽象工厂模式的区别?

工厂方法模式:

  • 一个抽象产品类,可以派生出多个具体产品类。
  • 一个抽象工厂类,可以派生出多个具体过程类。
  • 每个具体工厂类只能创建一个具体产品类的实例。

抽象工厂模式:

  • 多个抽象产品类,每个抽象产品类可以派生出多个具体产品类。
  • 一个抽象工厂类,可以派生出多个具体工厂类。
  • 每个具体工厂类可以创建多个具体产品类的实例。

主要区别:

  • 工厂方法模式只有一个抽象产品类,而抽象工厂模式有多个抽象产品类。
  • 工厂方法模式的具体工厂类只能创建一个具体产品类的实例,而抽象工厂模式可以创建多个具体产品类的实例。

参考:《大话设计模式》

 

 

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值