最近在学习设计模式,主要通过阅读大话设计模式,来学习,学习之余,做一个学习笔记。
需求:编写一个计算器类。
最初设计:新建计算机类,封装两个数值类,按照MVC的思想去实现,dao层封装四个方法,分别是增删改查,在实现类中去实现,然后业务层判断客户端传来的具体数值,更具操作符不同,选择调用不同的Dao层方法。
代码:
/**
* @author 123
* 计算器类
*/
public class Calc {
private double numA;
private double numB;
public double getNumA() {
return numA;
}
public void setNumA(double numA) {
this.numA = numA;
}
public double getNumB() {
return numB;
}
public void setNumB(double numB) {
this.numB = numB;
}
}
/**
* @author 123
* Dao层方法
*/
public interface ICalcDao {
double add(Calc calc);
double subtraction(Calc calc);
double multiply(Calc calc);
double divide(Calc calc);
}
package calc;
/**
* @author 123
* Dao层实现类
*/
public class CalcDaoImpl implements ICalcDao{
@Override
public double add(Calc calc) {
// TODO Auto-generated method stub
return calc.getNumA()+calc.getNumB();
}
@Override
public double subtraction(Calc calc) {
// TODO Auto-generated method stub
return calc.getNumA()-calc.getNumB();
}
@Override
public double multiply(Calc calc) {
// TODO Auto-generated method stub
return calc.getNumA()*calc.getNumB();
}
@Override
public double divide(Calc calc) {
// TODO Auto-generated method stub
return calc.getNumA()/calc.getNumB();
}
}
package calc;
/**
* @author 123
* 业务层接口
*/
public interface ICalcService {
double result(double numA,double numB,String operator);
}
package calc;
/**
* @author 123
* 业务层实现类
*/
public class CalcServiceImpl implements ICalcService {
@Override
public double result(double numA, double numB, String operator) {
// TODO Auto-generated method stub
ICalcDao icalc = new CalcDaoImpl();
Calc calc = new Calc();
Double result = null;
calc.setNumA(numA);
calc.setNumB(numB);
if ("+".equals(operator)) {
result = icalc.add(calc);
} else if ("-".equals(operator)) {
result = icalc.subtraction(calc);
} else if ("*".equals(operator)) {
icalc.multiply(calc);
} else if ("/".equals(operator)) {
if(numB==0){
System.out.println("除数不能为0");
return -1;
}
result =icalc.divide(calc);
} else {
System.out.println("请输入正确的操作符类型");
return -1;
}
return result;
}
}
package calc;
import java.util.Scanner;
import static java.lang.System.*;
/**
* @author 123
* 客户端类
*/
public class Client {
public static void main(String[] args) {
double numA = 0;
double numB = 0;
String operator = null;
try {
Scanner sc = new Scanner(System.in);
System.out.println("请输入需要运算的第一个数字");
numA = sc.nextDouble();
System.out.println("请输入需要运算的第二个数字");
numB = sc.nextDouble();
System.out.println("请输入需要运算的规则");
operator = sc.next();
} catch (Exception e) {
// TODO Auto-generated catch block
System.out.println("您输入的数字类型不合法");
e.printStackTrace();
exit(0);
}
ICalcService calcService = new CalcServiceImpl();
double result = calcService.result(numA, numB, operator);
System.out.println("结果为"+result);
}
}
阅读设计模式后设计:
把操作封装成不同的类,新建抽象操作类,封装两个用于计算的遍历和一个用于得到结果抽象方法,新建加减乘除类继承操作类,实现得到结果类,新建工厂类,设置静态方法,返回值为抽象操作类,根据不同的操作符,新建不同的算术类(即加减乘除类 向上转型),然后在客户端里进行调用工厂类,得到抽象类,继而调用抽象类中抽象方法,但是因为是向上转型,子类中重写了父类的得到结果的方法,所以是调用了对应子类的方法,这里主要运用的是多态的思想,一句比较经典的话是向上转型,会遗忘子类中独有的方法,引用对像会调用父类独有的和子类重写父类的方法。
代码:
package calc2;
/**
* @author 123
* 操作类
*/
public abstract class Operator {
private double numA;
private double numB;
public abstract double result();
public double getNumA() {
return numA;
}
public void setNumA(double numA) {
this.numA = numA;
}
public double getNumB() {
return numB;
}
public void setNumB(double numB) {
this.numB = numB;
}
}
package calc2;
/**
* @author 123
* 加法类
*/
public class Add extends Operator {
@Override
public double result() {
// TODO Auto-generated method stub
return getNumA() + getNumB();
}
}
其他减法除法类类似。。。。。。。。。。。。
package calc2;
/**
* @author 123
* 工厂类
*/
public class CalcFactory {
public static Operator getResult(String operator) {
Operator opera = null;
if ("+".equals(operator)) {
opera = new Add();
} else if ("-".equals(operator)) {
opera = new Subtraction();
} else if ("*".equals(operator)) {
opera = new Multiply();
} else if ("/".equals(operator)) {
opera = new Divide();
}
return opera;
}
}
package calc2;
import java.util.Scanner;
import static java.lang.System.*;
/**
* @author 123
* 客户端类
*/
public class Client {
public static void main(String[] args) {
double numA = 0;
double numB = 0;
String operator = null;
try {
Scanner sc = new Scanner(System.in);
System.out.println("请输入需要运算的第一个数字");
numA = sc.nextDouble();
System.out.println("请输入需要运算的第二个数字");
numB = sc.nextDouble();
System.out.println("请输入需要运算的规则");
operator = sc.next();
} catch (Exception e) {
// TODO Auto-generated catch block
System.out.println("您输入的数字类型不合法");
e.printStackTrace();
exit(0);
}
Operator operator2 = CalcFactory.getResult(operator);
operator2.setNumA(numA);
operator2.setNumB(numB);
System.out.println("结果为"+operator2.result());
}
}
两种方式比较,第一种,是惯用的MVC框架,虽然也运用到面向对象的思想,但是没有考虑到程序的扩展性,如果要增加其他算术方法,接口层和业务层都要有改动,改动面积大,但是感觉不是这样啊,即便是下面的简单工厂模式而言,如果增加一个根号运算,得在新加一个根号运算类,然后在工厂类里面增加相应的条件判断,这样看下来,二者都是要改动啊,而且改动看来也是差不多的,,,,,以后再慢慢体会吧