披萨项目为例,使用工厂模式设计
需求:方便披萨品种扩展,便于维护,要能运行时扩展
披萨族(组)设计类图
假设只有原料不同,其他操作如烘焙、切割、打包相同,就把prepare方法设置为抽象方法
一般设计如下
//披萨族抽象类 public abstract class Pizza { protected String name; public abstract void prepare(); public void bake() { System.out.println(name + " baking;"); } public void cut() { System.out.println(name + " cutting;"); } public void box() { System.out.println(name + " boxing;"); } public void setName(String name) { this.name = name; } }
public class CheesePizza extends Pizza { public void prepare() { super.setName("CheesePizza"); System.out.println(name + " preparing;"); } }
public class GreekPizza extends Pizza { public void prepare() { super.setName("GreekPizza"); System.out.println(name + " preparing;"); } }
public class PepperPizza extends Pizza { public void prepare() { super.setName("PepperPizza"); System.out.println(name + " preparing;"); } }
public class OrderPizza { public OrderPizza() { Pizza pizza = null; String orderType; do { orderType = getType(); if (orderType.equals("cheese")) { pizza = new CheesePizza(); } else if (orderType.equals("greek")) { pizza = new GreekPizza(); } else if (orderType.equals("pepper")) { pizza = new PepperPizza(); } else { break; } pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); } while (true); } private String getType() { try { BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in)); System.out.println("input pizza type:"); String pizzaType = bufferedReader.readLine(); return pizzaType; } catch (Exception ex) { ex.printStackTrace(); return ""; } } }
public class PizzaStore { public static void main(String[] args){ OrderPizza orderPizza; orderPizza=new OrderPizza(); } }
这种设计有个问题就是,如果有新品种,那就要在披萨族中添加(即实现Pizza抽象类),再在OrderPizza类中添加else if判断,同样如果删除披萨品种也要修改这两个地方
简单工厂模式就可以把OrderPizza中创建Pizza部分(if else 变化 部分)抽出来
1、简单工厂模式:定义了一个创建对象的类,由这个类来封装实例化对象的行为
public class SimplePizzaFactory { public Pizza createPizza(String orderType){ Pizza pizza=null; if (orderType.equals("cheese")) { pizza = new CheesePizza(); } else if (orderType.equals("greek")) { pizza = new GreekPizza(); } else if (orderType.equals("pepper")) { pizza = new PepperPizza(); } return pizza; } }
public class OrderPizza { SimplePizzaFactory simplePizzaFactory; public OrderPizza(SimplePizzaFactory simplePizzaFactory) { setFactory(simplePizzaFactory); } public void setFactory(SimplePizzaFactory simplePizzaFactory) { this.simplePizzaFactory = simplePizzaFactory; Pizza pizza = null; String orderType; do { orderType = getType(); pizza = simplePizzaFactory.createPizza(orderType); pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); } while (true); } private String getType() { try { BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in)); System.out.println("input pizza type:"); String pizzaType = bufferedReader.readLine(); return pizzaType; } catch (Exception ex) { ex.printStackTrace(); return ""; } } } OrderPizza 改造后,就要使用简单工厂创建披萨实例
public class PizzaStore { public static void main(String[] args){ OrderPizza orderPizza; orderPizza=new OrderPizza(new SimplePizzaFactory()); } }
这样的简单工厂设计,增删披萨品种时只需在披萨族中增删披萨种类,和修改披萨工厂中方法,不需要改OrderPizza类
2、工厂方法模式:定义了一个创建对象的抽象方法,由子类决定要实例化的类。工厂方法模式将对象的实例化推迟到子类
假如要在伦敦和纽约开披萨分店,地域特色不同,披萨工厂也就不同了,也就是工厂是可变的了,那么为了不让OrderPizza类依赖于工厂,就把制作pizza方法变为抽象方法,OrderPizza类也就是抽象类了,也就是把工厂的实现放到子类去实现,伦敦工厂实现伦敦工厂方法,纽约工厂实现纽约工厂方法
开始有个Pizza族,现在又有个Pizza工厂族,即OrderPizza
工厂方法模式设计方案:将披萨项目里的披萨对象实例化功能抽象成抽象方法,在不同加盟店具体实现功能
public abstract class OrderPizza { public OrderPizza() { Pizza pizza = null; String orderType; do { orderType = getType(); pizza=createPizza(orderType); pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); } while (true); } public abstract Pizza createPizza(String orderType); private String getType() { try { BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in)); System.out.println("input pizza type:"); String orderType = bufferedReader.readLine(); return orderType; } catch (Exception ex) { ex.printStackTrace(); return ""; } } }
public class LDCheesePizza extends Pizza { public void prepare() { super.setName("LDCheesePizza"); System.out.println(name+" preparing;"); } }
public class LDPepperPizza extends Pizza { public void prepare() { super.setName("LDPepperPizza"); System.out.println(name+"preparing;"); } }
public class NYCheesePizza extends Pizza { public void prepare() { super.setName("NYCheesePizza"); System.out.println(name+"preparing;"); } }
public class NYPepperPizza extends Pizza { public void prepare() { super.setName("NYPepperPizza"); System.out.println(name+"preparing;"); } }
public class LDOrderPizza extends OrderPizza { public Pizza createPizza(String orderType) { Pizza pizza = null; if (orderType.equals("cheese")) { pizza = new LDCheesePizza(); } else if (orderType.equals("pepper")) { pizza = new LDPepperPizza(); } return pizza; } }
public class NYOrderPizza extends OrderPizza { public Pizza createPizza(String orderType) { Pizza pizza=null; if(orderType.equals("cheese")){ pizza=new NYCheesePizza(); }else if(orderType.equals("pepper")){ pizza=new NYPepperPizza(); } return pizza; } }
public class PizzaStore { public static void main(String[] args){ OrderPizza orderPizza; // orderPizza=new LDOrderPizza(); orderPizza=new NYOrderPizza(); } }
简单工厂和工厂方法模式,看上去没有大的区别,但是在大型项目中,工厂方法模式就比较好,灵活性比较好点
3、抽象工厂模式:定义了一个接口用于创建相关或有依赖关系的对象族,而无需明确指定具体类(简单工厂演化)
public interface AbsFactory { Pizza createPizza(String orderType); }
public class LDFactory implements AbsFactory { public Pizza createPizza(String orderType) { Pizza pizza = null; if (orderType.equals("cheese")) { pizza = new LDCheesePizza(); } else if (orderType.equals("pepper")) { pizza = new LDPepperPizza(); } return pizza; } }
public class NYFactory implements AbsFactory { public Pizza createPizza(String orderType) { Pizza pizza=null; if(orderType.equals("cheese")){ pizza=new NYCheesePizza(); }else if(orderType.equals("pepper")){ pizza=new NYPepperPizza(); } return pizza; } }
public class OrderPizza { private AbsFactory absFactory; public OrderPizza(AbsFactory absFactory) { setFactory(absFactory); } public void setFactory(AbsFactory factory) { Pizza pizza = null; String orderType; this.absFactory = factory; do { orderType=getType(); pizza=absFactory.createPizza(orderType); if(pizza!=null){ pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); } } while (true); } public String getType() { try { BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(System.in)); System.out.println("input pizza type:"); String orderType=bufferedReader.readLine(); return orderType; }catch (Exception ex){ ex.printStackTrace(); return ""; } } }
public class PizzaStore { public static void main(String[] args){ AbsFactory absFactory; OrderPizza orderPizza; absFactory=new LDFactory(); orderPizza=new OrderPizza(absFactory); } }
4、依赖抽象原则
变量不要持有具体类的引用
不要让类继承自具体类,要继承自抽象类或接口
不要覆盖基类中已实现的方法