在谈工厂之前,先阐述一个观点:那就是在实际程序设计中,为了设计灵活的多态代码,代码中尽量不使用new去实例化一个对象,那么不使用new去实例化对象,剩下可用的方法就可以选择使用工厂方法,原型复制等去实例化这个对象,好处就是客户端并不知道这个实例化的对象的实际实现,从而可以将这个对象随意替换成我们需要的不同实现
工厂方法(Factory Method)
概念:定义一个用于创建对象的接口,让子类决定实例化哪个类.它使一个类的实例化延迟到其子类
结构图:
抽象工厂(Abstract Factory)
概念: 提供一个创建一系列相关或相互依赖对象的接口,而无需指定他们具体的类.
结构图:
单例模式(Singleton Pattern)
概念: 保证一个类仅有一个实例,并提供一个访问它的全局访问点
结构图:
很长一段时间我都无法理解抽象工厂和工厂方法的区别,现在我的理解是
1. 抽象工厂是提供创建一组产品类的接口的一个类(工厂),它只提供创建这个类的接口,至于具体如何创建,创建的是这个类的什么子类,这些都不是抽象工厂关心的范畴,换句话说,我们在很多设计模式例子所看到的使用具体工厂继承抽象工厂来生成产品的例子,只是抽象工厂的其中一种实现,也就是说抽象工厂仅仅是定义了一组生产产品的接口,一个没有实现的抽象工厂仅仅定义了这样一组接口,是无法使用的.而生产的实现是需要依赖其他设计模式的,例如工厂方法,原型模式.按照我的理解,单纯的谈论抽象工厂,它应该只包含下面这样的定义
public abstract class ABFactory { public abstract Product1 createProduct1(); public abstract Product2 createProduct2(); }
2. 在定义中我们看到AbstractFactory拥有具体的ConcreteFactory实现,这个实现的方式其实就是工厂方法,他将具体生产product的方法实现延迟到了子类
3. 为了生产产品,首先我们要获取工厂,而由于工厂的无状态性,往往会将工厂作为单例使用,所以我们创建和获取工厂的方法使用单例来实现
下面是一个例子
抽象工厂类
package factory; import product.Body; import product.Head; import java.util.HashMap; import java.util.Map; /** * Created with IntelliJ IDEA. * User: zhenwei.liu * Date: 13-7-31 * Time: 下午11:32 * To change this template use File | Settings | File Templates. */ public abstract class ModuleFactory { // 对于抽象工厂而言,由于instance有多种实现 // 所以此处使用一个instanceMap存储所有的Factory实现 // 如果只有一个instance,那么多线程环境下我们将只能使用过一种类型的Factory public static String CAT_MODULE_FACTORY = "cat_module_factory"; public static String DOG_MODULE_FACTORY = "dog_module_factory"; // 单例工厂列表 private static Map<String, ModuleFactory> instanceMap = new HashMap<String, ModuleFactory>(); static { // 舍弃延迟加载,直接减给所有factory注册进Map里 // 好处是不要每增加一个具体工厂就去修改createFactory里的判断你条件 // 只需要在这个注册代码块里将新的工厂注册进去,而这个注册代码块可以 // 写在别的类或者配置文件里来实现,这样就达成了新增工厂和创建工厂解耦 instanceMap.put(CAT_MODULE_FACTORY, new CatModuleFactory()); instanceMap.put(DOG_MODULE_FACTORY, new DogModuleFactory()); } private static Object lockObj = new Object(); // 动态返回单例的工厂 public static ModuleFactory createFactory(String factoryType) { if (factoryType == null) throw new RuntimeException("Param factoryType cannot be null"); // 延迟实例化各不同该类型的工厂 // 舍弃延迟加载技术,则可以省去if条件判断 // if (instanceMap.get(factoryType) == null) { // synchronized (lockObj) { // if (instanceMap.get(factoryType) == null) { // if (factoryType.equals(CAT_MODULE_FACTORY)) { // instanceMap.put(CAT_MODULE_FACTORY, new CatModuleFactory()); // } else if (factoryType.equals(DOG_MODULE_FACTORY)) { // instanceMap.put(DOG_MODULE_FACTORY, new DogModuleFactory()); // } else { // throw new RuntimeException("FactoryType " + factoryType + " undefined"); // } // } // } // } return instanceMap.get(factoryType); } // 工厂方法 public abstract Head createHead(); public abstract Body createBody(); }
具体工厂类
package factory; import product.Body; import product.CatBody; import product.CatHead; import product.Head; /** * Created with IntelliJ IDEA. * User: zhenwei.liu * Date: 13-7-31 * Time: 下午11:36 * To change this template use File | Settings | File Templates. */ public class CatModuleFactory extends ModuleFactory { @Override public Head createHead() { return new CatHead(); } @Override public Body createBody() { return new CatBody(); } } package factory; import product.Body; import product.DogBody; import product.DogHead; import product.Head; /** * Created with IntelliJ IDEA. * User: zhenwei.liu * Date: 13-7-31 * Time: 下午11:36 * To change this template use File | Settings | File Templates. */ public class DogModuleFactory extends ModuleFactory { @Override public Head createHead() { return new DogHead(); } @Override public Body createBody() { return new DogBody(); } }
产品类
package product; /** * Created with IntelliJ IDEA. * User: zhenwei.liu * Date: 13-8-1 * Time: 上午12:24 * To change this template use File | Settings | File Templates. */ public abstract class Body { public abstract void dance(); } package product; /** * Created with IntelliJ IDEA. * User: zhenwei.liu * Date: 13-8-1 * Time: 上午12:27 * To change this template use File | Settings | File Templates. */ public class CatBody extends Body { @Override public void dance() { System.out.println("A caaat's body is dancing crazily!!"); } } package product; /** * Created with IntelliJ IDEA. * User: zhenwei.liu * Date: 13-8-1 * Time: 上午12:27 * To change this template use File | Settings | File Templates. */ public class DogBody extends Body { @Override public void dance() { System.out.println("A dooog's body is dancing!"); } } package product; /** * Created with IntelliJ IDEA. * User: zhenwei.liu * Date: 13-8-1 * Time: 上午12:24 * To change this template use File | Settings | File Templates. */ public abstract class Head { public abstract void eat(); } package product; /** * Created with IntelliJ IDEA. * User: zhenwei.liu * Date: 13-8-1 * Time: 上午12:29 * To change this template use File | Settings | File Templates. */ public class CatHead extends Head { @Override public void eat() { System.out.println("A caaat's head is eating fast"); } } package product; /** * Created with IntelliJ IDEA. * User: zhenwei.liu * Date: 13-8-1 * Time: 上午12:29 * To change this template use File | Settings | File Templates. */ public class DogHead extends Head { @Override public void eat() { System.out.println("A dooog's head is eating"); } }
测试类
import factory.CatModuleFactory; import factory.DogModuleFactory; import factory.ModuleFactory; import product.Body; import product.Head; /** * Created with IntelliJ IDEA. * User: zhenwei.liu * Date: 13-8-1 * Time: 上午12:00 * To change this template use File | Settings | File Templates. */ public class Test { // 通过工厂解耦方法内animal实现 // 这个方法就是多态代码的实现 public static void act(ModuleFactory factory) { Head head = factory.createHead(); Body body = factory.createBody(); head.eat(); body.dance(); } public static void main(String[] args) { ModuleFactory factory = ModuleFactory.createFactory(ModuleFactory.CAT_MODULE_FACTORY); act(factory); factory = ModuleFactory.createFactory(ModuleFactory.DOG_MODULE_FACTORY); act(factory); } }
输出
A caaat's head is eating fast
A caaat's body is dancing crazily!!
A dooog's head is eating
A dooog's body is dancing!
抽象工厂的优点和缺点
优点
1.分离具体类和客户端的耦合,客户端只需要根据Head和Body这种产品抽象类来编写代码,而具体实现则由具体的factory来决定(如act()方法)
2.易于替换产品系列,要使用不同的产品系列,只需要替换具体的factory即可(如act()方法)
3.可以保持产品系列的一致性,不会出现CatHead和DogBody这样的组合(至少基于工厂方法的抽象工厂是如此)
缺点
抽象工厂对新产品的支持度较差(无论是基于工厂方法还是基于原型),加入新加入了一个Foot的product,则需要在抽象工厂中加入抽象方法createFoot()并在所有的具体工厂中实现这个createFoot()方法.
工厂方法的优点和缺点
很大程度上工厂方法的优点和缺点与抽象工厂是类似的,因为工厂方法是抽象工厂的实现之一
优点
用户只需要针对抽象的产品类或接口进行编码,而不必关注具体实现类,达到与产品类解耦和多态的目的
缺点
工厂方法是一个产品-创建器的平行结构,每增加一个产品则需要增加一个创建器,应对变化的能力较差
单例模式的优点和缺点
优点
1.使用单例可以节省系统资源
2.可以严格控制对唯一实例的访问
3. GoF中文版写的优点全都没看懂....
缺点: 没看懂