1.1 介绍 1.1.1 概念 工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。 1.1.2 生活化 比如我们去超市买东西,作为顾客,我们不需要关注商品从何而来,只要是超市上架有货,我们就可以购买,这里的超市就相当于一个工厂模式中的工厂,用来管理商品。 1.1.3 优缺点 优点: 1、一个调用者想创建一个对象,只要知道其名称就可以了。 2、扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。 3、屏蔽产品的具体实现,调用者只关心产品的接口。 缺点:每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。 使用场景: 1、日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方。 2、数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时。 3、设计一个连接服务器的框架,需要三个协议,”POP3”、”IMAP”、”HTTP”,可以把这三个作为产品类,共同实现一个接口。 注意事项:作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别是只需要通过 new 就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。 1.2.代码化 1.2.1 普通工厂模式 首先创建商品的共同接口:
package com.tl.skyLine.pattern.FactoryPattern; /** * Created by tl on 17/3/8. * 商品共同接口 */ public interface Product { //每一个商品都有说明介绍 public void explain(); }其次,创建商品实现类,香皂Soap和洗头膏Shampoo:
package com.tl.skyLine.pattern.FactoryPattern; /** * Created by tl on 17/3/8. */ public class Soap implements Product { @Override public void explain() { System.out.println("我是舒肤佳牌香皂!"); } } package com.tl.skyLine.pattern.FactoryPattern; /** * Created by tl on 17/3/8. */ public class Shampoo implements Product { @Override public void explain() { System.out.println("我是海飞丝牌洗头膏!"); } }最后,建工厂类,也就是超市:
package com.tl.skyLine.pattern.FactoryPattern; /** * Created by tl on 17/3/8. */ public class Supermarket { public Product sell(String name) { if ("soap".equals(name)) { return new Soap(); } else if ("shampoo".equals(name)) { return new Shampoo(); } else { System.out.println("该商品本商店暂时未上架!"); return null; } } }我们来测试一下:
package com.tl.skyLine.pattern.FactoryPattern; /** * Created by tl on 17/3/8. */ public class FactoryTest { public static void main(String[] args) { Supermarket market = new Supermarket(); Product sender = market.sell("soap"); sender.explain(); } }输出:我是舒肤佳牌香皂! 1.2.2 多个工厂方法模式 是对普通工厂方法模式的改进,在普通工厂方法模式中,如果传递的字符串出错,则不能正确创建对象,而多个工厂方法模式是提供多个工厂方法,分别创建对象。 我们修一下超市类:
public class Supermarket { public Product sellSoap() { return new Soap(); } public Product sellShampoo() { return new Shampoo(); } }测试类如下:
public class FactoryTest { public static void main(String[] args) { Supermarket market = new Supermarket(); Product sender = market.sellSoap(); sender.explain(); } }输出:我是舒肤佳牌香皂! 1.2.3 静态工厂方法模式 将上面的多个工厂方法模式里的方法置为静态的,不需要创建实例,直接调用即可。
public class Supermarket { public static Product sellSoap() { return new Soap(); } public static Product sellShampoo() { return new Shampoo(); } } public class FactoryTest { public static void main(String[] args) { Product sender = Supermarket.sellSoap(); sender.explain(); } }输出:我是舒肤佳牌香皂! 总结:当有大量拥有共同接口(属性)的对象(商品)时,我们可以可以通过工厂方法模式(超市)进行创建,在以上的三种模式中,第一种如果传入的字符串有误,不能正确创建对象,第三种相对于第二种,不需要实例化工厂类,所以,大多数情况下,我们会选用第三种——静态工厂方法模式。
2.1 介绍 工厂方法模式有一个问题就是,类的创建依赖工厂类,也就是说,如果想要拓展程序,必须对工厂类进行修改,这违背了闭包原则,所以,从设计角度考虑,有一定的问题,如何解决?就用到抽象工厂模式,创建多个工厂类,这样一旦需要增加新的功能,直接增加新的工厂类就可以了,不需要修改之前的代码。 抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。 2.2 生活化 假如所有的超市只卖一种商品,比如A超市只卖香皂,B超市只卖洗头膏,如果我们想去买洗面奶,怎么办呢,那就只能找一家只卖洗面奶的超市C才可以,所有抽象工厂模式就是把卖商品的超市抽取公共接口,也就是的所谓的工厂工厂。 2.3 代码化 香皂Soap和洗头膏Shampoo实例不变,创建超市抽象接口:
package com.tl.skyLine.pattern.FactoryPattern; /** * Created by tl on 17/3/8. */ public interface SuperMarket { public Product sell(); }卖香皂的超市:
package com.tl.skyLine.pattern.FactoryPattern; /** * Created by tl on 17/3/8. */ public class SoapMarket implements SuperMarket { @Override public Product sell() { return new Soap(); } }卖洗头膏的超市:
package com.tl.skyLine.pattern.FactoryPattern; /** * Created by tl on 17/3/8. */ public class ShampooMarket implements SuperMarket { @Override public Product sell() { return new Shampoo(); } }测试:
public class FactoryTest { public static void main(String[] args) { SuperMarket market = new SoapMarket(); Product product = market.sell(); product.explain(); } }这样,我们扩展商品种类的时候就不需要修改封装好的超市接口,通过新开超市去卖新的商品即可!(此处仅是根据设计模式开闭原则假设的生活例子)
工厂方法模式与抽象工厂模式最大的区别在于,在工厂方法模式中,工厂创造的是一个产品(就是代码中的超市类),而在抽象工厂模式中,工厂创造的是一个产品族(就是代码中的超市类的接口)。