大话设计模式读书笔记(简单工厂模式)
人物:小菜,大鸟
事件:小菜去求职,求职题目是用Java等任意一种面向对象语言,实现一个计算机控制台程序,要求输入两个数和运算符,得到结果
简单工厂模式:
1.小菜实现一道面试题,输入两个数和运算符,得到结果,小菜初次实现后,大鸟指出了3个缺点
2.小菜进行了改进,完成了功能,但思路却不是出题人的思路
3.大鸟为了小菜更好地理解,借曹操吟诗解释了面向对象
4.小菜尝试用封装和继承实现了简单工厂模式,最后让代码达到了灵活性好,可扩展,可复用
小菜的初次实现
@Slf4j public class Program { public static void main(String[] args) { log.info("每输入一个数字或者运算符号请敲回车"); Scanner scanner = new Scanner(System.in); BigDecimal A = scanner.nextBigDecimal(); String calculateChar = scanner.next(); BigDecimal numberB = scanner.nextBigDecimal(); if (calculateChar.equalsIgnoreCase("-")) { log.info(A.subtract(numberB).toString()); } if (calculateChar.equalsIgnoreCase("+")) { log.info(A.add(numberB).toString()); } if (calculateChar.equalsIgnoreCase("*")) { log.info(A.multiply(numberB).toString()); } if (calculateChar.equalsIgnoreCase("/")) { log.info(A.divide(numberB).toString()); } } }
大鸟指出了代码缺点:
1.第一个数字的命名不规范
2.if...else...语句,会无用判断三次
3.如果numberB输入的是0,则代码会报错
小菜的再次尝试
@Slf4j public class Program { public static void main(String[] args) { log.info("每输入一个数字或者运算符号请敲回车"); Scanner scanner = new Scanner(System.in); BigDecimal numberA = scanner.nextBigDecimal(); String calculateChar = scanner.next(); BigDecimal numberB = scanner.nextBigDecimal(); String result = ""; try { switch (calculateChar) { case "+": result = numberA.add(numberB).toString(); case "-": result = numberA.subtract(numberB).toString(); case "*": result = numberA.multiply(numberB).toString(); case "/": if (BigDecimal.ZERO.equals(numberB)) { log.info("除数不能是0"); } else { result = numberA.divide(numberB).toString(); } break; } log.info("最后计算出的数字是:{}", result); } catch (Exception e) { log.info("输入有误,请重新输入"); } } }
大鸟评价:就目前来说,实现功能是没有问题了,但还需确认这样设计是否符合出题人的题意
面向对象编程
作者以曹操写诗,刻板,改诗,刻板,改诗,再刻板举例,改一个字,就需要全部重新刻板,而活字印刷,则改一字就重印一字即可:
1.改字,即只需重新印刷要改之字 --可维护
2.活体印刷这次用了,下次还可以继续使用 --可复用
3.一篇文章若要加字,则再刻一字即可 --可拓展
4.可改变排版格式,横排竖排都可 --灵活性好
小菜尝试将代码复用(业务的封装)
@Slf4j
public class Program {
public static void main(String[] args) {
try {
log.info("每输入一个数字或者运算符号请敲回车");
Scanner scanner = new Scanner(System.in);
BigDecimal numberA = scanner.nextBigDecimal();
String calculateChar = scanner.next();
BigDecimal numberB = scanner.nextBigDecimal();
String result = getResult(numberA, numberB, calculateChar);
if (StringUtils.isEmpty(result)) {
log.info("运算符请输入 + - * 或 /");
} else {
log.info("最后计算出的数字是:{}", result);
}
} catch (Exception e) {
log.info("输入有误,请重新输入");
}
}
public static String getResult(BigDecimal numberA, BigDecimal numberB, String calculateChar) {
switch (calculateChar) {
case "+":
return numberA.add(numberB).toString();
case "-":
return numberA.subtract(numberB).toString();
case "*":
return numberA.multiply(numberB).toString();
case "/":
if (BigDecimal.ZERO.equals(numberB)) {
log.info("除数不能是0");
} else {
return numberA.divide(numberB).toString();
}
break;
}
return null;
}
}
大鸟:
业务和界面已经分离,现在已经用了面向对象三大特性之一的封装了,那么另外两个继承和多态改怎么运用到这个例子中呢?
现在要求你加一个开根号的运算符
小菜:
那直接在switch上加一个开根号就行(其实以前我也是,有什么需要就加什么,完全没有考虑过设计模式的问题,使得代码很长又不好维护)
大鸟:
原来getResult()接口的内容被暴露了出来,增加了风险,可能不小心修改错误会导致一大片逻辑错误
小菜尝试用继承方式实现
@Data
public class Operation {
private BigDecimal numberA = BigDecimal.ZERO;
private BigDecimal numberB = BigDecimal.ZERO;
public String getResult() {
BigDecimal result = BigDecimal.ZERO;
return result.toString();
}
}
将加减乘除分出来封装好(加法如下),依次继承,供以调用,如果要增加开根号,则再写一个子类即可
public class OperationAdd extends Operation {
@Override
public String getResult() {
BigDecimal result = getNumberA().add(getNumberB());
return result.toString();
}
}
大鸟:思路不错,接下来就是考虑如何实例化对象的问题了,下面是简单工厂模式,可以参考解决这个问题
简单工厂类:
public class OperationFactory {
public static Operation createOperate(String operate) {
Operation oper = null;
switch (operate) {
case "+":
oper = new OperationAdd();
case "-":
//oper = new OperationSub();
case "*":
//oper = new OperationMul();
case "/":
//oper = new OperationDiv();
break;
}
return oper;
}
}
客户端代码:
public static void main(String[] args) {
Operation oper;
oper = OperationFactory.createOperate("+");
oper.setNumberA(new BigDecimal("1"));
oper.setNumberB(new BigDecimal("2"));
String result = oper.getResult();
log.info("运算结果为:{}", result);
}
大鸟:就这样,只要输入运算符号,工厂就能实例化对象,通过多态,返回父类的方式得到结果

大鸟:编程是一门技术,更加是一门艺术,要考虑让代码更加简练,更容易维护,容易拓展和复用。

浙公网安备 33010602011771号