在构造我们的对象的时候,很容易出现设计的缺陷,比如严重依赖某个细节实现,或者不符合迪米特法则, 不符合里式替换原则,这些都可以通过简单工单的设计模式解决。
简单通常的设计UML图如下所示:
1、 使用示例
这里我们实现一个非常简单的例子,获取不同颜色的书籍,代码如下:
定义书籍的共性方法,以及其功能
abstract static class Book {// 描述public void desc() {System.out.println("这是一本书");}// 获取书籍的颜色public abstract Color getColor();// 获取书籍的价格public abstract float getPrice();}
根据书籍的定义实现红色书和绿色书
static class GreenBook extends Book {@Overridepublic Color getColor() {return Color.GREEN;}@Overridepublic float getPrice() {return 123;}}static class RedBook extends Book {@Overridepublic Color getColor() {return Color.RED;}@Overridepublic float getPrice() {return 124;}}
在往常的代码开发中,如果我们需要RedBook,只需要 Book book = new RedBook() 这样的方式客户端对RedBook类严重依赖,没有达到解耦的目的,也简洁的违背了迪米特法则,因为上层代码对Book 的实现有直接关系。所以,这里我们需要抽象一个创建者的对象,也就是我们讨论的工厂对象,定义如下:
// 定义创建者,也就是工程对象interface Factory {Book getInstance(String className);Book getInstance(Class<? extends Book> clazz);}// 实现具体工厂static class ConcreteFactor implements Factory {private ConcreteFactor() {}private static Factory factory = new ConcreteFactor();// 使用单例模式,全局唯一工厂对象public static Factory getFactory() {return factory;}@Overridepublic Book getInstance(String className) {try {return (Book) Class.forName(className).newInstance();} catch (Exception e) {return null;}}@Overridepublic Book getInstance(Class<? extends Book> clazz) {try {return clazz.newInstance();} catch (Exception e) {return null;}}}
- 上层代码逻辑需要使用Book,只需要传递类型或者字符串即可, 比如
public static void main(String[] args) {// 单例模式获取Factory的实例Factory factory = ConcreteFactor.getFactory();// 符合迪米特法则,上层代码不需要直接连接底层代码Book book = factory.getInstance(RedBook.class);printBookInfo(book);book = factory.getInstance(GreenBook.class.getName());printBookInfo(book);}// 里式替换原则private static void printBookInfo(Book book) {assert book != null;System.out.println("书的价格是:" + book.getPrice() + "颜色是:" + book.getColor());}
- 程序运行结果
书的价格是:124.0颜色是:java.awt.Color[r=255,g=0,b=0]书的价格是:123.0颜色是:java.awt.Color[r=0,g=255,b=0]
2、多工厂模式
上面的代码中,我们仅仅使用到了一个工厂实例对象。在一些复杂的场景中,创建一个产品对象无比复杂,势必造成代码的巨大,这个时候我们可以精细化工厂,如上面的书籍的示例中,我们可以实现创建红色书籍的工厂 RedBookConcreteFactory & GreenBookConcreteFactory 等,当然也可以创建一个创建工厂的工厂,不过就显然有些冗余了!其类图如下所示:
3、总结
- 工厂模式非常容易拓展,假如需要蓝色的书籍,我们只需要定义一个 BlueBook 继承 Book 即可;
- 上层代码不需要知道对象的创建过程,接触模块之间的代码耦合
- 通过工厂获取的对象均为抽象,不是具体的细节,这显然符合里式替换原则
- 有的设计模式中,将工厂的创建产品的方法抽象为静态的方法,这种称之为静态工厂的设计模式
- 事实上也可以通过工厂模式实现单例模式,甚至可以使用Map
实现单例的缓存模型
