先看一个小故事:
你是一个工匠,得到一个紧急的任务,要求刻版印刷 “喝酒唱歌 人生真爽” ,由于任务紧急,你不得不通宵,终于刻好了。
第二天,客户突然觉得 “喝酒唱歌” 这几个字有点俗,觉得改成 “对酒当歌 人生真爽” 比较好,你又熬夜刻制好了。
第三天,客户想了想,觉得 “人生真爽” ,太过直接,要求改成 “对酒当歌 人生几何” ,虽然你很生气,但是你只能忍着,你又熬夜重新刻制好。
任务完事了,你就想,如果再遇到了改来改去的客户,有什么好办法能减少你的工作量呢?
没错,你可以把几个字分开刻,不要把所有字都刻在一起,而是刻八个板,每个板刻一个字,如果有变动,不用所有的工作都重头做,只需要修改变动的部分就可以。工作量一下减少了一半。
这就是中国古代的活字印刷啊。
通过这样的方法,可以做到 可维护(只需要修改有变动的字)、可复用(两次需求重复的字不用再刻制一遍)、可扩展(若要加字,只需要另外刻字加入即可)、灵活性好(字的排列方式横竖可以随意改)
看完这个小故事,下面思考一个题目:
使用面向对象的语言,要求输入两个数和运算符号,得到结果。
1
最简单的做法,我们可以获取用户输入的两个数字和运算符号,判断运算符号直接进行运算就可以得到结果;
(此处为了偷懒,我只写了加法和乘法两种运算)
- //此处我只写了加法和乘法两种运算
- public static void main(String[] args) {
- Scanner input=new Scanner(System.in);
- System.out.println("请输入第一个数字:");
- int num1=input.nextInt();
- System.out.println("请输入运算符:");
- String yunsuanfu=input.next();
- System.out.println("请输入第二个数字:");
- int num2=input.nextInt();
- switch(yunsuanfu){
- case "+":
- System.out.println(num1+yunsuanfu+num2+"="+(num1+num2));
- break;
- case "*":
- System.out.println(num1+yunsuanfu+num2+"="+(num1*num2));
- break;
-
- }
-
- }
但这显然有问题,根本没有使用到面向对象的思想。假如把需求修改成写一个计算器,现在的代码能不能复用呢?
2
下面我们尝试修改,先让业务逻辑和界面逻辑分开。
业务逻辑代码:
- public class Yunsuan1 {
- public static int getResult(int num1, int num2, String yunsuanfu) {
- int result = 0;
- switch (yunsuanfu) {
- case "+":
- result = num1 + num2;
- break;
- case "*":
- result = num1 * num2;
- break;
-
- }
- return result;
- }
- }
界面逻辑代码:
- import java.util.Scanner;
-
- public class Test1 {
- public static void main(String[] args) {
- Scanner input=new Scanner(System.in);
- System.out.println("请输入第一个数字:");
- int num1=input.nextInt();
- System.out.println("请输入运算符:");
- String yunsuanfu=input.next();
- System.out.println("请输入第二个数字:");
- int num2=input.nextInt();
- int result= Yunsuan1.getResult(num1,num2,yunsuanfu);
- System.out.println("结果是:"+result);
-
- }
- }
如上的代码使用了面向对象的封装。
现在假如要写一个计算器的应用程序,就可以把业务逻辑的代码复用了。
不单是web程序、手机等移动系统的软件也可以复用。
3
现在我们来思考,假如要添加一个指数运算,此时就要修改整个逻辑代码文件,有可能失误把已经写好的加法运算改错,又比如,公司新增了一个岗位,现在要求你为公司的薪资管理做维护,公司就必须把整个逻辑代码文件给你修改,你心中小算盘一打,“TMD,公司给我的工资这么低,这下有机会了。”
比如switch是你自己的时候,你把你的工资加20%。本来是让你加一个功能,却使得原来良好的功能代码发生了变化,这风险太大了。
那么我们应该做到 修改其中一种运算,不影响其他运算。我们来使用面向对象的继承和多态。
从不同的运算抽象出Yunsuan父类
- package com.qing.jdgc;
-
- public abstract class Yunsuan {
- public abstract void getResult(int num1,int num2);
- }
子类继承 Yunsuan父类,不同的运算(加法、乘法、指数运算)执行的运算操作是不一样的,重写计算的方法。
- package com.qing.jdgc;
-
- public class Jiafa extends Yunsuan{
- @Override
- public void getResult(int num1, int num2) {
- System.out.println(num1+"和"+num2+"执行加法运算后结果是:"+(num1+num2));
-
- }
- }
- package com.qing.jdgc;
-
- public class Chengfa extends Yunsuan {
-
- @Override
- public void getResult(int num1, int num2) {
- System.out.println(num1 + "和" + num2 + "执行乘法运算后结果是:" + (num1 * num2));
- }
- }
- package com.qing.jdgc;
-
- public class Zhishu extends Yunsuan{
- @Override
- public void getResult(int num1, int num2) {
- System.out.println(num1+"和"+num2+"执行指数运算后结果是:"+(Math.pow(num1,num2)));
- }
- }
根据不同的运算符号实例化出不同的对象(多态),接下来执行不同的运算
- package com.qing.jdgc;
-
- public class Factory {
-
- public static Yunsuan createYunsuan(String yunsuanfu){
- Yunsuan yunsuan = null;
- switch(yunsuanfu){
- case "+":
- yunsuan=new Jiafa();
- break;
- case "*":
- yunsuan=new Chengfa();
- break;
- case "^":
- yunsuan=new Zhishu();
- break;
-
- }
- return yunsuan;
- }
-
-
-
- }
界面逻辑
- package com.qing.jdgc;
-
- import java.util.Scanner;
-
- public class Test {
- public static void main(String[] args) {
- Scanner input=new Scanner(System.in);
- System.out.println("请输入第一个数字:");
- int num1=input.nextInt();
- System.out.println("请输入运算符:");
- String yunsuanfu=input.next();
- System.out.println("请输入第二个数字:");
- int num2=input.nextInt();
- Factory.createYunsuan(yunsuanfu).getResult(num1,num2);
- }
- }
结果
接下来,回到正题,简单工厂模式。
简单工厂模式又叫静态工厂方法,属于类创建型模式。
特点如下
可以根据参数的不同,返回不同的实例。
简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
如上的最后一次的代码就使用了简单工厂模式,Factory类就可以根据不同的运算符返回不同的实例。