设计模式-第1章(简单工厂模式)
简单工厂模式
- 计算器1的代码
- 计算器2的代码
- 活字印刷,面向对象
- 业务的封装
- 降低耦合
- 简单工厂模式
- UML 类图
计算器1的代码
import java.util.Scanner;
public class Test {
public static void main(String[] args){
System.out.println("**********************************************");
System.out.println("《大话设计模式》代码样例");
System.out.println();
Scanner sc = new Scanner(System.in);
System.out.println("请输入数字A:");
String A = sc.nextLine();
System.out.println("请选择运算符号(+、-、*、/):");
String B = sc.nextLine();
System.out.println("请输入数字B:");
String C = sc.nextLine();
double D = 0d;
if (B.equals("+"))
D = Double.parseDouble(A) + Double.parseDouble(C);
if (B.equals("-"))
D = Double.parseDouble(A) - Double.parseDouble(C);
if (B.equals("*"))
D = Double.parseDouble(A) * Double.parseDouble(C);
if (B.equals("/"))
D = Double.parseDouble(A) / Double.parseDouble(C);
System.out.println("结果是:"+D);
System.out.println();
System.out.println("**********************************************");
}
}
计算器1的代码中变量命名不规范,if 语句重复判断,除数为 0 未作判断。
计算器2的代码
import java.util.Scanner;
public class Test {
public static void main(String[] args){
System.out.println("**********************************************");
System.out.println("《大话设计模式》代码样例");
System.out.println();
try {
Scanner sc = new Scanner(System.in);
System.out.println("请输入数字A:");
double numberA = Double.parseDouble(sc.nextLine());
System.out.println("请选择运算符号(+、-、*、/):");
String strOperate = sc.nextLine();
System.out.println("请输入数字B:");
double numberB = Double.parseDouble(sc.nextLine());
double result = 0d;
switch(strOperate){
case "+":
result = numberA + numberB;
break;
case "-":
result = numberA - numberB;
break;
case "*":
result = numberA * numberB;
break;
case "/":
result = numberA / numberB;
break;
}
System.out.println("结果是:"+result);
}
catch(Exception e){
System.out.println("您的输入有错:"+e.toString());
}
System.out.println();
System.out.println("**********************************************");
}
}
计算器2的代码虽然实现了功能,但是本质上还是面向过程的思维方式。程序不容易维护,不容易复用,不容易扩展。
活字印刷,面向对象
没有活字印刷之前,如果想要改变印刷的内容,就要全部重新雕刻。有了活字印刷,就可以加字减字来改变内容。
活字印刷要改变内容时只需要更改对应的字即可,实现了可维护性。
这些字在下次印刷的时候可以重复使用,实现了可复用性。
如果印刷的文章想要加字,只需将另刻的字加入即可,实现了可扩展性。
字的排列可以时竖排,可以是横排,此时只需要将字移动即可。灵活性更好。
面向对象的程序设计可以通过封装,继承,多态把程序的耦合度降低。
传统印刷术的问题就是在于所有的字都刻在同一面板上造成耦合度太高。
好的设计模式使得程序更加灵活,容易修改,易于复用。
业务的封装
将业务逻辑和界面逻辑分开,让它们之间的耦合度下降。
Operation 运算类:
public class Operation {
public static double getResult(double numberA,
double numberB, String operate) {
double result = 0d;
switch (operate) {
case "+":
result = numberA + numberB;
break;
case "-":
result = numberA - numberB;
break;
case "*":
result = numberA * numberB;
break;
case "/":
result = numberA / numberB;
break;
case "pow":
result= java.lang.Math.pow(numberA,numberB);
break;
}
return result;
}
}
界面逻辑
import java.util.Scanner;
public class Test {
public static void main(String[] args){
System.out.println("**********************************************");
System.out.println("《大话设计模式》代码样例");
System.out.println();
try {
Scanner sc = new Scanner(System.in);
System.out.println("请输入数字A:");
double numberA = Double.parseDouble(sc.nextLine());
System.out.println("请选择运算符号(+、-、*、/):");
String strOperate = sc.nextLine();
System.out.println("请输入数字B:");
double numberB = Double.parseDouble(sc.nextLine());
double result = Operation.getResult(numberA,numberB,strOperate);
System.out.println("结果是:"+result);
}
catch(Exception e){
System.out.println("您的输入有错:"+e.toString());
}
System.out.println();
System.out.println("**********************************************");
}
}
降低耦合
如果要在程序中加入新的运算方法,就要将整个Operation 运算类改变。不利于程序的修改和灵活的扩展。继续降低程序的耦合。将Operation 中的每一种运算方式都分离出来,成为一个独立的类。使得在修改其中一种运算方式的时候,其它的运算方式不受影响。
Operation 类
public abstract class Operation {
public double getResult(double numberA, double numberB){
return 0d;
}
}
Add 类
public class Add extends Operation {
public double getResult(double numberA, double numberB){
return numberA + numberB;
}
}
Sub 类
public class Sub extends Operation {
public double getResult(double numberA, double numberB){
return numberA - numberB;
}
}
Mul 类
public class Mul extends Operation {
public double getResult(double numberA, double numberB){
return numberA * numberB;
}
}
Div 类
public class Div extends Operation {
public double getResult(double numberA, double numberB){
if (numberB == 0){
System.out.println("除数不能为0");
throw new ArithmeticException();
}
return numberA / numberB;
}
}
Operation 更改为一个抽象类,然后每一种具体的方法继承了 Operation 类,重写了 getResult() 方法。这样如果修改了任意一个运算类,就不会影响到其他的代码,降低了耦合。
简单工厂模式
现在要做的时,在运算的时候,实例化对应的运算类对象,然后调用运算类的方法。
现在考虑用一个单独的类,来实例化对象,这个类就是一个工厂。
工厂就是创造对象的类。
public class OperationFactory {
public static Operation createOperate(String operate){
Operation oper = null;
switch (operate) {
case "+":
oper = new Add();
break;
case "-":
oper = new Sub();
break;
case "*":
oper = new Mul();
break;
case "/":
oper = new Div();
break;
}
return oper;
}
}
在工厂中,工厂通过运算符号来实例化出合适的对象。通过多态,返回父类。
import java.util.Scanner;
public class Test {
public static void main(String[] args){
System.out.println("**********************************************");
System.out.println("《大话设计模式》代码样例");
System.out.println();
try {
Scanner sc = new Scanner(System.in);
System.out.println("请输入数字A:");
double numberA = Double.parseDouble(sc.nextLine());
System.out.println("请选择运算符号(+、-、*、/):");
String strOperate = sc.nextLine();
System.out.println("请输入数字B:");
double numberB = Double.parseDouble(sc.nextLine());
Operation oper = OperationFactory.createOperate(strOperate);
double result = oper.getResult(numberA,numberB);
System.out.println("结果是:"+result);
}
catch(Exception e){
System.out.println("您的输入有错:"+e.toString());
}
System.out.println();
System.out.println("**********************************************");
}
}
在界面逻辑中,调用工厂类中的方法,拿到了实例化的对象,然后通过对象得到了计算的结果。
编程不能只满足代码运行正确就行。要考虑让代码更加简洁,更加容易维护,容易扩展和复用。
UML 类图
下面来对图例进行解释。
动物的矩形框,代表一个类。类图分为三层,第一层为类名,如果是抽象类,类名为斜体。第二层是类的特性,就是类的属性。第三层是类的操作,就是类的方法。
’+‘ 号表示 public ,’-‘ 号表示 private,’#‘ 表示protected。
飞翔的矩形框,顶端有《interface》显示。表示为一个接口图。第一行为接口名称,第二行为接口方法。接口还有一种表示法,俗称棒棒糖表示法。如图中的唐老鸭类实现了说人话的接口。
继承的关系用空心三角形 + 实线来表示。如图中的鸟继承了动物类。
实现接口用空心三角形 + 虚线来表示。如大雁实现了飞翔的接口。
关联关系用实线箭头来表示。当一个类知道另一个类时,可以用关联。如企鹅和气候。
class Penguin extends Bird{
// 在企鹅 Penguin 中,引用了气候 Climate
private Climate climate;
}
聚合关系用空心的菱形+实线箭头表示。聚合表示一种弱的拥有关系,体现的是A对象可以包含B对象、但 B对象 不是 A对象的一部分。如图中的雁群和大雁的关系。
class WideGooseAggregate {
//在雁群WideGooseAggregate类中有大雁数组对象arrayWideGoose
private WideGoose[] arrayWideGoose;
}
合成关系用实心的菱形+实线箭头来表示。合成关系的连线两端可以有数字,被称为基数。合成体现了严格的部分和整体的关系,部分和整体的生命周期一样。如图中 鸟和翅膀的关系,一只鸟有两只翅膀,并且鸟和翅膀的生命周期是相同的。如果一个类有无数个实例,则用n来表示。关联关系,聚合关系也可以有基数。
class Bird {
//在鸟Bird类中声明一个翅膀Wing对象wing
private Wing wing;
public Bird() {
//初始化时,实例化翅膀Wing,它们之间同时生成
wing = new Wing();
}
}
依赖关系,用虚线箭头来表示。如图中动物和氧气和水的关系。动物要有生命力,动物依赖于氧气和水。
abstract class Animal {
public Metabolism (Oxygen oxygen, Water water){
}
}