Head First设计模式——工厂模式

本章需要了解实例化不应该总是公开地进行,也会认识到初始化经常造成"耦合"问题,还会了解工厂模式如何从复杂的依赖中解耦。

当使用"new"时,的确是在实例化一个具体类,用的确实是实现,而非接口。

代码捆绑着具体类会导致代码变得更脆弱,更缺乏弹性。

当有一些需要实例化的具体类时,究竟需要实例化哪个类,要在运行时由一些条件来决定。

这样的代码,一旦有变化或扩展,就必须重新打开这段代码进行检查和修改。通常这样修改过的代码将造成部分系统更难维护和更新,而且也更容易犯错。

针对接口编程,可以隔离掉以后系统可能发生的一大堆改变。因为,如果代码是针对接口写的,那么通过多态,它可以与任何新类实现该接口。但是,当代码使用大量的具体类时,等于自找麻烦。因为一旦加入新的具体类,就必须改变代码。想用新的具体类型来扩展代码,必须重新打开它。(该设计应该"对扩展开放,对修改关闭")

解决办法:

封装创建对象的代码

首先,将创建对象的代码抽离出来,然后把这部分代码放到另一个对象中,这个新对象只管如何创建。

我们称这个新对象为"工厂"

工厂(factory)处理创建对象的细节。

利用静态方法定义一个简单的工厂是非常常见的技巧,常被称为静态工厂。因为不需要使用创建对象的方法来实例化对象,不能通过继承来改变创建方法的行为!

简单工厂其实不是一个设计模式,反而比较像一种编程习惯。

从简单工厂到工厂方法:由一个对象负责所有具体类的实例化(简单工厂)变成由一群子类负责实例化(工厂方法)

实例化的责任被移到一个"方法"中,此"方法"就如同是一个"工厂"。

工厂方法用来处理对象的创建,并将这样的行为封装在子类中。这样,客户程序中关于超类的代码就和子类对象创建代码解耦了。

protected abstract Product factoryMethod(String type)

abstract:工厂方法是抽象的

Product:返回类型

factoryMethod:方法名

String type:参数(可为空)

所有的工厂模式都用来封装对象的创建。工厂方法模式(Factory Method Patten)通过让子类决定该创建的对象是什么,来达到将对象创建的过程封装的目的。

工厂方法模式的定义:

工厂方法模式定义了一个创建对象的接口,并由子类决定要实例化的类是哪一个。工厂方法的实质是将实例化推迟到子类!

工厂方法模式封装具体类型的实例化。抽象的Creator提供了一个创建对象的方法的接口,因此也称"工厂方法"。在抽象的Creator中,任何其他实现的方法,都可能使用这个工厂方法所制造出来的产品,但只有子类真正实现这个工厂方法并创建产品。

工厂方法让子类决定要实例化的类是哪一个。所谓的"决定",并不是指模式允许子类本身在运行时决定,而是指在编写创建类时,无需知道实际创建的产品是哪一个。

简单工厂与工厂方法之间的差异:

  • 简单工厂把所有的事情在一个地方处理完,工厂方法却是创建了一个框架,让子类决定要如何实现。
  • 简单工厂不具备工厂方法的弹性,因为简单工厂不能变更正在创建的产品。

"工厂"的好处:将创建对象的代码集中在一个对象(简单工厂)或方法(工厂方法)中,可以避免代码中的重复,并且更方便以后的维护。同时,这也使得用户在实例化对象时,只会依赖于接口,而不是具体类。这可以帮助针对接口编程而不针对实现编程。使代码更具有弹性。

封装起创建对象的代码,就可以对抽象编码,将客户代码和真实的实现解耦。

如何查看对象依赖关系?

当直接实例化一个对象时,就是在依赖它的具体实现类!

很清楚地,代码中减少对于具体类的依赖是件好事。

OO设计原则:要依赖抽象,不要依赖具体类!——————依赖倒置原则(Dependency Inversion Principle)

该原则说明了:不能让高层组件依赖低层组件,并且不管高层或低层组件,都应该依赖于抽象。(所谓"高层"组件,是由其他低层组件定义其行为的类)——————依赖倒置原则中的依赖

依赖倒置原则中的倒置指的是:和一般OO设计的思考方式完全相反——低层组件依赖高层的抽象。

下面的指导方针能够避免在OO设计中违反依赖倒置原则:

  • 变量不可以持有具体类的引用。(如果使用new,就会持有具体类的引用。可以改用工厂来避免这样的做法)
  • 不要让类派生自具体类。(如果派生自具体类,就会依赖具体类。可以派生自一个抽象接口或抽象类)
  • 不要覆盖基类中已实现的方法。(如果覆盖基类已实现的方法,那么基类就不是一个真正适合被继承的抽象。基类中实现的方法,应该由所有的子类共享)

尽量达到这些原则,而不是随时都要遵循。要深化体验这些方针,将这些方针内化成思考的一部分,那么在设计时,就会知道何时有足够的理由违反这样的原则。例如,有一个不像是会改变的类,那么在代码中直接实例化具体类也就没什么大碍。(PS:程序中实例化的字符串对象,因为字符串无法改变)当有个类可能改变时,可以采用工厂方法来封装改变。


抽象工厂模式:

抽象工厂模式提供了一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。

抽象工厂允许用户使用抽象的接口来创建一组相关的产品,而不需要知道(或关心)实际产出的具体产品是什么。如此一来,用户就从具体的产品中被解耦。

抽象工厂定义了一个接口,所有的具体工厂都必须实现此接口,这个接口包含了一组方法用来生产产品。


抽象工厂的每个方法实际上看起来都像是工厂方法。每个方法都被声明成抽象,而子类的方法覆盖这些方法来创建某些对象。


小结

要点:

  • 所有的工厂都是用来封装对象的创建
  • 简单工厂虽然不是真正的设计模式,但仍不失为一种简单的方法将客户从具体类中解耦
  • 工厂方法使用继承:把对象的创建委托给子类,子类实现工厂方法来创建对象
  • 抽象工厂使用对象组合:对象的创建被实现在工厂接口所暴露出来的方法中
  • 所有工厂模式都通过减少应用程序和具体类之间的依赖促进松耦合
  • 工厂方法允许类将实例化延迟到子类进行
  • 抽象工厂创建相关的对象家族,而不需要依赖它们的具体类
  • 依赖倒置原则,指导我们避免依赖具体类型,而是尽量依赖抽象
  • 工厂针对抽象编程 ,而不要针对具体类编程

posted on 2022-04-02 17:21  天真的柏拉图  阅读(55)  评论(0)    收藏  举报