一、提出需求
分析一个关于生产披萨的项目:要便于披萨种类的扩展,要便于维护。
(1)披萨的种类很多(比如:GreekPizza、CheesePizza 等)
(2)披萨的制作有 prepare,bake,cut,box
(3)完成披萨店订购功能。
二、使用传统的方式来完成
思路分析:可以得到,将披萨做成一个抽象类,里面声明所有披萨都需要的功能,然后根据需要来继承该类,再创建一个订购类,可以根据用户输入的披萨名称来生产不同种类的披萨。
UML 类图:
Demo:不使用设计模式
Pizza 相关类
1 /**
2 * 将 pizza 类做成抽象类
3 */
4 public abstract class Pizza {
5 //名字
6 protected String name;
7
8 //准备原材料, 不同的披萨不一样,因此,我们做成抽象方法
9 public abstract void prepare();
10
11 //烘焙
12 public void bake() {
13 System.out.println(name + " baking;");
14 }
15
16 //切割
17 public void cut() {
18 System.out.println(name + " cutting;");
19 }
20
21 //打包
22 public void box() {
23 System.out.println(name + " boxing;");
24 }
25
26 public void setName(String name) {
27 this.name = name;
28 }
29
30 }
31
32 public class GreekPizza extends Pizza{
33 @Override
34 public void prepare() {
35 System.out.println(" 给希腊披萨 准备原材料 ");
36 }
37 }
38
39 public class CheesePizza extends Pizza {
40 @Override
41 public void prepare() {
42 System.out.println(" 给制作奶酪披萨 准备原材料 ");
43 }
44 }
订购披萨
1 public class OrderPizza {
2
3 //构造器
4 public OrderPizza() {
5 Pizza pizza = null;
6 String orderType; //订购披萨的类型
7 do {
8 orderType = getType();
9 if (orderType.equals("greek")) {
10 pizza = new GreekPizza();
11 pizza.setName("希腊披萨");
12 } else if (orderType.equals("cheese")) {
13 pizza = new CheesePizza();
14 pizza.setName("奶酪披萨");
15 } else {
16 System.out.println("此类披萨还未上架");
17 break;
18 }
19 //输出披萨制作过程
20 pizza.prepare();
21 pizza.bake();
22 pizza.cut();
23 pizza.box();
24
25 } while (true);
26 }
27
28 //声明一个方法,可以获取客户希望订购的披萨种类
29 private String getType() {
30 try {
31 BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
32 System.out.println("input pizza 种类:");
33 String str = bufferedReader.readLine();
34 return str;
35 } catch (IOException e) {
36 e.printStackTrace();
37 return "";
38 }
39 }
40 }
测试类:
1 public class PizzaStore {
2
3 public static void main(String[] args) {
4 new OrderPizza();
5 }
6 }
效果:
此时,我们需要另外上架一个新的 PepperPizza 披萨,对代码做出对应的修改。
创建一个 PepperPizza 类:
1 public class PepperPizza extends Pizza {
2 @Override
3 public void prepare() {
4 // TODO Auto-generated method stub
5 System.out.println(" 给胡椒披萨准备原材料 ");
6 }
7 }
对订购披萨类进行修改:
1 public OrderPizza() {
2 Pizza pizza = null;
3 String orderType; //订购披萨的类型
4 do {
5 orderType = getType();
6 if (orderType.equals("greek")) {
7 pizza = new GreekPizza();
8 pizza.setName("希腊披萨");
9 } else if (orderType.equals("cheese")) {
10 pizza = new CheesePizza();
11 pizza.setName("奶酪披萨");
12 } else if (orderType.equals("pepper")) {
13 pizza = new PepperPizza();
14 pizza.setName("胡椒披萨");
15 } else {
16 System.out.println("此类披萨还未上架");
17 break;
18 }
19 //输出披萨制作过程
20 pizza.prepare();
21 pizza.bake();
22 pizza.cut();
23 pizza.box();
24
25 } while (true);
26 }
类图:
三、传统的方式的优缺点
1、优点是比较好理解,简单易操作。
2、缺点是违反了设计模式的 OCP 原则,即对扩展开发,对修改关闭。即当我们给类增加新功能的时候,尽量不修改代码,或者尽可能少修改代码。
3、比如这时要新增一个 Pizza 的种类(Pepper披萨),需要做如下修改:
① 增加一个对应的 PepperPizza类;
② 凡是订购 Pizza 的代码都需要修改;(可能有一处或者多处都使用)
4、改进的思路分析
分析:修改代码可以接受,但是如果我们在其他的地方也有创建 Pizza的代码,就意味着,也需要修改,而创建 Pizza 的代码,往往有多处。
思路:把创建 Pizza 对象封装到一个类中,这样我们有新的 Pizza 种类时,只需要修改该类即可。其他有创建到Pizza对象的代码就不需要修改了。