设计模式——工厂方法 Java源代码
2015-12-22 12:52
344 查看
本程序改编自《Head First Design Patterns》中的Pizza例子,我本学期早上经常吃包子。
总共有11个类:
一个工厂父类 ( Creator)
两个工厂子类 ( Concrete Creator)
一个包子父类 ( Product )
六个包子子类 ( Concrete Product )
一个Main类 ( 程序的入口 )
图:ConcreteProduct 继承 Product,ConcreteCreator 继承 Creator,ConcreateProduct 依赖 ConcreateProduct。其实,有一条线没有显示出来:Creator 依赖 Product。
Head First 说,这体现了依赖倒置原则:因为高层模块(Creator)依赖抽象类(Product),底层模块(ConcreteProduct)也依赖抽象类(Product)。
补充说明:我个人感觉,严格的说:ConcreteProduct 和Product 之间不是依赖,而是继承关系。勉强说的话,算作一种”非常非常强的依赖“吧。Head First : The ConcreteProduct class depends on the Product abstraction too, because they implement the Product interface (we’re using the “interface” in the general sense) in the Product abstraction class.
1. 工厂方法模式的优势:如果位于武汉的工厂需要增加一种口味的包子(这种类似的事情经常发生),比如”热干包子“,那么工厂方法模式只用增加一个包子子类,然后修改武汉工厂子类就行了。
2. 没有工厂方法模式的劣势:如果位于武汉的工厂需要增加一种口味的包子(这种类似的事情经常发生),比如”热干包子“,那么所有用于在武汉创建包子的
if( … ) { new … }
else( ) { … }
的代码都在后面增加一个
if( 热干 ) {new ReGanBaoZiWuhan() }
else( ) { … }
改一个地方还比较轻松,但是关键在于很有可能在很多地方都要用到包子。假设100个地方都要创建包子,那么100个地方的if( … )else( )“的代码都要修改!这完全是反人类,违反了开闭原则。
更多深入分析,查看我的这一篇博客,进入目录->第三个标题
总共有11个类:
一个工厂父类 ( Creator)
两个工厂子类 ( Concrete Creator)
一个包子父类 ( Product )
六个包子子类 ( Concrete Product )
一个Main类 ( 程序的入口 )
图:ConcreteProduct 继承 Product,ConcreteCreator 继承 Creator,ConcreateProduct 依赖 ConcreateProduct。其实,有一条线没有显示出来:Creator 依赖 Product。
Head First 说,这体现了依赖倒置原则:因为高层模块(Creator)依赖抽象类(Product),底层模块(ConcreteProduct)也依赖抽象类(Product)。
补充说明:我个人感觉,严格的说:ConcreteProduct 和Product 之间不是依赖,而是继承关系。勉强说的话,算作一种”非常非常强的依赖“吧。Head First : The ConcreteProduct class depends on the Product abstraction too, because they implement the Product interface (we’re using the “interface” in the general sense) in the Product abstraction class.
一个工厂父类
[code]package factoryMethod; public abstract class BaoZiFactory { // 把具体的 new操作 “下放”到子类中。 abstract BaoZi createBaoZi(String baoZiName); // 这个方法不改变,即无论包子里面的馅是什么,***包子的流程是一样的(都是准备馅,然后蒸30分钟) final public BaoZi makeBaoZi(String baoZiName) { BaoZi baoZi = createBaoZi(baoZiName); baoZi.prepare(); baoZi.steam(); return baoZi; } }
两个工厂子类
[code]package factoryMethod; public class BaoZiFactoryChangsha extends BaoZiFactory { public BaoZiFactoryChangsha() { System.out.println("Constructor of BaoZiFactory in Changsha\n"); } @Override // 依据传进来的参数,决定new什么包子 BaoZi createBaoZi(String baoZiName) { BaoZi baoZi = null; if(baoZiName.equals("酱肉")) { baoZi = new ChangshaJiangRouBaoZi(); } else if(baoZiName.equals("青菜")) { baoZi = new ChangshaQingCaiBaoZi(); } else if(baoZiName.equals("鲜肉")) { baoZi = new ChangshaXianRouBaoZi(); } return baoZi; } }
[code]package factoryMethod; public class BaoZiFactoryWuhan extends BaoZiFactory { public BaoZiFactoryWuhan() { System.out.println("Constructor of BaoZiFactory in Wuhan\n"); } @Override // 依据传进来的参数,决定new什么包子 BaoZi createBaoZi(String baoZiName) { BaoZi baoZi = null; if(baoZiName.equals("酱肉")) { baoZi = new WuhanJiangRouBaoZi(); } else if(baoZiName.equals("青菜")) { baoZi = new WuhanQingCaiBaoZi(); } else if(baoZiName.equals("鲜肉")) { baoZi = new WuhanXianRouBaoZi(); } return baoZi; } }
一个包子父类
[code]package factoryMethod; import java.util.ArrayList; // 父类:包子,抽象出包子共有的特性 // 有道词典:steamed stuffed bun (蒸的,填充的,小圆面包) // 由于这三个单词加起来过长,我命名放弃采纳英文命名法,直接使用汉语拼音命名法BaoZi public abstract class BaoZi { private String name; ArrayList<String> stuffings = new ArrayList<String> (); public void setName(String n) { this.name = n; } public String getName() { return name; } void prepare() { System.out.println("Prepare " + name); System.out.println("Stuffings are:"); for(String stuff: stuffings) { System.out.println(stuff); } } void steam() { System.out.println("Steam for 30 minutes"); } //覆盖toString (这个方法继承自java.lang.Object) public String toString() { StringBuffer display = new StringBuffer(); display.append("---- " + name + " ----\n"); for(String stuff : stuffings) { display.append(stuff + "\n"); } return display.toString(); } }
六个包子子类
[code]package factoryMethod; public class ChangshaJiangRouBaoZi extends BaoZi { public ChangshaJiangRouBaoZi() { setName("长沙酱肉包子"); stuffings.add("辣椒"); stuffings.add("炸酱"); stuffings.add("肉末"); stuffings.add("干子"); } }
[code]package factoryMethod; public class ChangshaQingCaiBaoZi extends BaoZi { public ChangshaQingCaiBaoZi() { setName("长沙青菜包子"); stuffings.add("辣椒"); stuffings.add("包菜"); stuffings.add("茄子"); } }
[code]package factoryMethod; public class ChangshaXianRouBaoZi extends BaoZi { public ChangshaXianRouBaoZi() { setName("长沙鲜肉包子"); stuffings.add("辣椒"); stuffings.add("鲜肉"); } }
[code]package factoryMethod; public class WuhanJiangRouBaoZi extends BaoZi { public WuhanJiangRouBaoZi() { setName("武汉酱肉包子"); stuffings.add("炸酱"); stuffings.add("肉末"); stuffings.add("干子"); } }
[code]package factoryMethod; public class WuhanQingCaiBaoZi extends BaoZi { public WuhanQingCaiBaoZi() { setName("武汉青菜包子"); stuffings.add("包菜"); stuffings.add("茄子"); } }
[code]package factoryMethod; public class WuhanXianRouBaoZi extends BaoZi { public WuhanXianRouBaoZi() { setName("武汉鲜肉包子"); stuffings.add("鲜肉"); } }
一个Main类
[code]package factoryMethod; public class Main { public static void main(String[] args) { BaoZiFactory wuhanFactory = new BaoZiFactoryWuhan(); BaoZiFactory changshaFactory = new BaoZiFactoryChangsha(); BaoZi baoZi = null; baoZi = wuhanFactory.makeBaoZi("酱肉"); System.out.println("Caitao made a " + baoZi.getName() + "\n"); baoZi = wuhanFactory.makeBaoZi("青菜"); System.out.println("Caitao made a " + baoZi.getName() + "\n"); baoZi = changshaFactory.makeBaoZi("鲜肉"); System.out.println("Lucy made a " + baoZi.getName() + "\n"); baoZi = changshaFactory.makeBaoZi("青菜"); System.out.println("Lucy made a " + baoZi.getName() + "\n"); } }
运行结果
直接从eclipse复制过来的[code]Constructor of BaoZiFactory in Wuhan Constructor of BaoZiFactory in Changsha Prepare 武汉酱肉包子 Stuffings are: 炸酱 肉末 干子 Steam for 30 minutes Caitao made a 武汉酱肉包子 Prepare 武汉青菜包子 Stuffings are: 包菜 茄子 Steam for 30 minutes Caitao made a 武汉青菜包子 Prepare 长沙鲜肉包子 Stuffings are: 辣椒 鲜肉 Steam for 30 minutes Lucy made a 长沙鲜肉包子 Prepare 长沙青菜包子 Stuffings are: 辣椒 包菜 茄子 Steam for 30 minutes Lucy made a 长沙青菜包子
如果没有工厂方法模式
又要实现同样的功能怎么破?代码如下(理想输入条件,没有异常处理)[code]public BaoZi makeBaoZi(String place, String type) { BaoZi baoZi = null; if (place.equals("武汉")) { if (type.equals("酱肉")) { baoZi = new WuhanJiangRouBaoZi(); } else if (type.equals("青菜")) { baoZi = new WuhanQingCaiBaoZi(); } else if (type.equals("鲜肉")) { baoZi = new WuhanXianRouBaoZi(); } } else if (place.equals("长沙")) { if (type.equals("酱肉")) { baoZi = new ChangshaJiangRouBaoZi(); } else if (type.equals("青菜")) { baoZi = new ChangshaQingCaiBaoZi(); } else if (type.equals("鲜肉")) { baoZi = new ChangshaXianRouBaoZi(); } } baoZi.prepare(); baoZi.steam(); return baoZi; }
[code]优劣之分立马体现出来了!我们可以看到代码变短了(当然了,需要增加一些类作为“额外工作”,这是值得的) 创建包子的new操作“隐藏了”,取而代之的是一个factory对象调用createBaoZi方法 public BaoZi makeBaoZi(String place, String type) { BaoZiFactory factory = null; if(place.equals("武汉")) { factory = new BaoZiFactoryWuhan(); } else if(place.equals("长沙")) { factory = new BaoZiFactoryChangsha(); } BaoZi baoZi = factory.createBaoZi(type); baoZi.prepare(); baoZi.steam(); return baoZi; }
1. 工厂方法模式的优势:如果位于武汉的工厂需要增加一种口味的包子(这种类似的事情经常发生),比如”热干包子“,那么工厂方法模式只用增加一个包子子类,然后修改武汉工厂子类就行了。
[code]关键是下面的代码不变,放到哪里都一样,以不变应万变! BaoZiFactory factory = null; if(place.equals("武汉")) { factory = new BaoZiFactoryWuhan(); } else if(place.equals("长沙")) { factory = new BaoZiFactoryChangsha(); } BaoZi baoZi = factory.createBaoZi(type);
2. 没有工厂方法模式的劣势:如果位于武汉的工厂需要增加一种口味的包子(这种类似的事情经常发生),比如”热干包子“,那么所有用于在武汉创建包子的
if( … ) { new … }
else( ) { … }
的代码都在后面增加一个
if( 热干 ) {new ReGanBaoZiWuhan() }
else( ) { … }
[code]BaoZi baoZi = null; if (place.equals("武汉")) { if (type.equals("酱肉")) { baoZi = new WuhanJiangRouBaoZi(); } else if (type.equals("青菜")) { baoZi = new WuhanQingCaiBaoZi(); } else if (type.equals("鲜肉")) { baoZi = new WuhanXianRouBaoZi(); } *********增加的代码***************** else if(type.equals("热干")) { baoZi = new WuhanReGanBaoZi(); } ************************************ } else if (place.equals("长沙")) { if (type.equals("酱肉")) { baoZi = new ChangshaJiangRouBaoZi(); } else if (type.equals("青菜")) { baoZi = new ChangshaQingCaiBaoZi(); } else if (type.equals("鲜肉")) { baoZi = new ChangshaXianRouBaoZi(); } }
改一个地方还比较轻松,但是关键在于很有可能在很多地方都要用到包子。假设100个地方都要创建包子,那么100个地方的if( … )else( )“的代码都要修改!这完全是反人类,违反了开闭原则。
更多深入分析,查看我的这一篇博客,进入目录->第三个标题
相关文章推荐
- java中的泛型
- JAVA模拟各种请求方式访问RESTFUL
- Java中对类的主动引用和被动引用
- Eclipse SVN安装
- Myeclipse10.0版本部署按钮失效
- [springframework] - Difference between @Controller and @RestController
- SpringBoot初探(二)——打成war和自动部署
- java.io.Serializable浅析
- Java基础--IO流02(字符缓冲区、字节流、装饰设计模式)
- Java之JMX
- [javase学习笔记]-7.1 构造函数概述与默认构造函数
- JAVAEE之--------过滤器设置是否缓存(Filter)
- java extends/interface/implement三者的联系与区别
- java程序中加入@SuppressWarnings("serial")实践
- Java NIO与IO的区别和比较
- MD5带盐值的java加密算法
- Java API —— TreeMap类
- Java API —— HashMap类 & LinkedHashMap类
- spring-mvc环境搭建及helloworld的demo实现
- Think In Java 读后感