大二结束了java和java web的基础课程,大三开始自学各种框架,在看书和观看视频过程中发现自己设计模式知识的欠缺,使得自己学习的时候云里雾里,知其然不知其所以然,在某一篇博文中看到“框架是软件,而设计模式是软件的知识”,所以决定自己再扎实的学一遍设计模式,并且写下自己总结的文章,各种繁杂的定义就不写了,网上和书上一大堆,希望自己可以写的偏实际一点。(由于第一次写文章,水平有限,若有错误希望大家指正)
简单工厂模式
1.为什么需要使用工厂模式
其实这也是初学设计模式时经常会想到的问题,网上给的例子一般都太简单,虽然能够说明实现方式和原理,可总给人一种为了使用而使用的感觉,绕来绕去我还不如自己new一个对象
首先,工厂模式是为了解耦,“高内聚、低耦合”是所有软件设计者所追求的,很多设计模式也都是为了这个目的而存在。接下来我会用很大篇幅的代码一步一步的引出为什么需要简单工厂模式
在《大话设计模式》有一个写简单计算器的例子如下
public class Calculator {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入数字A");
Double numberA = scanner.nextDouble();
System.out.println("请输入运算符号(+、-、*、/)");
scanner.nextLine();//吃一个换行符
String operator = scanner.nextLine();
System.out.println("请输入数字B");
Double numberB = scanner.nextDouble();
Double result;
switch (operator) {
case "+":
result = numberA + numberB;
break;
case "-":
result = numberA - numberB;
break;
case "*":
result = numberA * numberB;
break;
case "/":
try {
result = numberA / numberB;
} catch (ArithmeticException e) {
System.out.println("除数不能为0");
return;
}
break;
default:
System.out.println("没有该运算规则");
return;
}
System.out.println("结果是:"+result);
}
}
这是初学者在学习java时最容易写出的代码,特别是刚刚学习C语言过后,我们来看一看上面的代码在设计上存在哪些问题
(1)没有使用到面向对象的思想
如果现在我们的身边有一个计算器,大家想一想它会是什么样的,首先我们会看到屏幕和各种按键,当正确的按下一系列按键后,我们会在屏幕上看到结果,可后面的具体运算过程我们是看不到的。接下来看上面的代码,输出打印语句类比为屏幕,输入语句是按键,剩下的case switch 定义变量等语句都是计算过程,而这些计算过程都是可以隐藏起来的,这样界面和业务逻辑完全分离,降低耦合性,便于程序维护。
修改过后代码如下
public class View {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入数字A");
Double numberA = scanner.nextDouble();
System.out.println("请输入运算符号(+、-、*、/)");
scanner.nextLine();//吃一个换行符
String operator = scanner.nextLine();
System.out.println("请输入数字B");
Double numberB = scanner.nextDouble();
Double result = null;
try {
result = Calculator.calculator(numberA,operator,numberB);
System.out.println("结果是:"+result);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class Calculator {
public static Double calculator(Double numberA,String operator,Double numberB) throws ArithmeticException{
double result;
switch (operator) {
case "+":
result = numberA + numberB;
break;
case "-":
result = numberA - numberB;
break;
case "*":
result = numberA * numberB;
break;
case "/":
try {
result = numberA / numberB;
} catch (ArithmeticException e) {
throw new ArithmeticException("被除数不能为0");
}
break;
default:
throw new ArithmeticException("没有这个运算规则");
}
return result;
}
}
这样就分离了业务逻辑和界面,但我们再看看这样的代码还有什么问题
(2)扩展性极差
如果有一天我们需要加上开方、平方等运算,所有的加减乘除等功能都得参与程序的编译,在增加功能的同时还有误修改源码的风险,违背开放闭合原则。
继续修改代码
abstract public class Operation {
private double a;
private double b;
abstract public double getResult() throws Exception;
//定义一个抽象类 其中有一个运算抽象方法
public double getA() {
return a;
}
public void setA(double a) {
this.a = a;
}
public double getB() {
return b;
}
public void setB(double b) {
this.b = b;
}
}
public class AddOperation extends Operation{
@Override
public double getResult() {
double result=super.getA()+super.getB();
return result;
}
}
public class SubOperation extends Operation{
@Override
public double getResult() {
double result=super.getA()-super.getB();
return result;
}
}
public class MulOperation extends Operation {
@Override
public double getResult() {
double result=super.getA()*super.getB();
return result;
}
}
public class SubOperation extends Operation{
@Override
public double getResult() {
double result=super.getA()-super.getB();
return result;
}
}
修改后的代码扩展性大大增强,当我们需要增加其他运算时,我们只需要让新类继承Operation类并实现getResult方法,不需要去修改其他功能模块的代码。可新问题来了,在运算的时候,我们需要有选择性的实例化某一个对象,这个时候就用到了简单工厂模式。
2.简单工厂模式的定义
虽然我真的特别特别特别的不喜欢那些臃肿的定义,不过在某些角度看来,为了让知识系统化,了解一些定义还是挺有必要的。不过在上定义之前,咱们先看看模式的结构
简单工厂模式包含如下角色:
Factory:工厂角色
Product:抽象产品角色
ConcreteProduct:具体产品角色
工厂角色(Creator)
是简单工厂模式的核心,它负责实现创建所有具体产品类的实例。工厂类可以被外界直接调用,创建所需的产品对象。(也就是我们在后面的OperationFactory类)
抽象产品角色(Product)
是所有具体产品角色的父类,它负责描述所有实例所共有的公共接口。(上面代码的Operation类)
具体产品角色(Concrete Product)
继承自抽象产品角色,一般为多个,是简单工厂模式的创建目标。工厂类返回的都是该角色的某一具体产品。(Operation的子类)
补齐后面的代码
public class OperationFactory {
public static Operation createOperation(char op) throws Exception{
switch (op) {
case '+':
return new AddOperation();
case '-':
return new SubOperation();
case '*':
return new MulOperation();
case '/':
return new DivOperation();
default:
throw new Exception("符号有误!");
}
}
}
public class Main {
public static void main(String[] args) {
Operation opr = null;
double a;
char op;
double b;
Scanner sc = new Scanner(System.in);
a = sc.nextDouble();
op = sc.next().charAt(0);
b = sc.nextDouble();
try {
opr=OperationFactory.createOperation(op);
opr.setA(a);
opr.setB(b);
System.out.println(opr.getResult());
}catch (Exception e)
{
System.out.println(e.getMessage());
}
}
}
最后最后最后,上定义!
简单工厂模式(Simple Factory Pattern):又称为静态工厂方法(Static Factory Method)模式,它属于类创建型模式。在简单工厂模式中,可以根据参数(也就是上述的各种运算符号)的不同返回不同类的实例(上述的运算方法子类)。简单工厂模式专门定义一个类(上述的OperationFactory类)来负责创建其他类的实例,被创建的实例通常都具有共同的父类(上述的Operation类)。
最后说一下自己的理解
简单工厂模式无非是对面向对象思想的一种体现,我需要什么,你就给我提供什么,通过继承和多态又将业务逻辑中的代码解耦,使得各个功能之间耦合度降低,便于程序扩展维护,当然有人会说,在增加新功能以后,我们依旧需要去修改工厂类的switch语句,这个问题就通过以后在写抽象工厂模式的总结的时候解答吧。