- 简单工厂模式:(参考https://www.jianshu.com/p/a9f397c4ff98)
- 定义:提供一个创建对象实例的功能,而无需关心其具体实现。被创建实例的类型可以使接口、抽象类,也可以是具体的类。简单工厂模式是属于创建型模式,又叫做静态工厂方法(Static Factory Method)模式,但不属于23种GOF设计模式之一。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例
- 说明:以我的理解,包含的角色,工厂,抽象的产品,具体的产品。工厂是通过不同的参数来产生具体产品的实例的,一般来说都是通过静态方法的,使用简单工厂的时候,通常不用创建简单工厂类的类实例,没有创建实例的必要。因此可以把简单工厂类实现成一个工具类,直接使用静态方法就可以了,也就是说简单工厂的方法通常都是静态的,所以也被称为静态工厂。如果要防止客户端无谓的创造简单工厂实例,还可以把简单工厂的构造方法私有化了(其实还有配置文件的)
- 类图
- 关键代码
- 就如同上面的示例,客户端通过简单工厂创建了一个实现接口的对象,然后面向接口编程,从客户端来看,它根本就不知道具体的实现是什么,也不知道是如何实现的,它只知道通过工厂获得了一个接口对象,然后就能通过这个接口来获取想要的功能。
- 疑问:上面的代码不就是吧new方法放进了工厂里面了嘛,放到mian里面和工厂里面有什么不同
- 图中红线框,就好比是一个组件的包装边界,表示接口、实现类和工厂类组合成了一个组件,在这个封装体里面,只有接口和工厂是对外的,也就是让外部知道并使用的,所以故意漏了一些在红线框外,而具体的实现类是不对外的,被完全包含在红线框内。对于客户端而言,只是知道了接口Api和简单工厂Factory,通过Factory就可以获得Api了,这样就达到了让Client在不知道具体实现类的情况下获取接口Api。所以看似简单的把“new这句话从客户端里面移动到了简单工厂里面,其实是有了质的变化的。
- 写法:
- 上面是一种,其实这种写法是有个缺点的,由于是从客户端在调用工厂的时候,传入选择的参数,这就说明客户端必须知道每个参数的含义,也需要理解每个参数对应的功能处理。这就要求必须在一定程度上,向客户暴露一定的内部实现细节。
- 写成可配置的简单工厂
- 当有了新的实现类过后,只要在配置文件(例如最简单的properties文件)里面配置上新的实现类就好了,在简单工厂的方法里面可以使用反射,当然也可以使用IoC/DI(控制反转/依赖注入,这个不在这里讨论)来实现,
- 优点:
- 帮助封装:简单工厂虽然很简单,但是非常友好的帮助我们实现了组件的封装,然后让组件外部能真正面向接口编程。
- 解耦:通过简单工厂,实现了客户端和具体实现类的解耦。如同上面的例子,客户端根本就不知道具体是由谁来实现,也不知道具体是如何实现的,客户端只是通过工厂获取它需要的接口对象。
- 缺点:
- 可能增加客户端的复杂度:如果通过客户端的参数来选择具体的实现类,那么就必须让客户端能理解各个参数所代表的具体功能和含义,这会增加客户端使用的难度,也部分暴露了内部实现
- 不方便扩展子工厂:私有化简单工厂的构造方法,使用静态方法来创建接口,也就不能通过写简单工厂类的子类来改变创建接口的方法的行为了。不过,通常情况下是不需要为简单工厂创建子类的。
- 什么时候选用简单工厂:
- 如果想要完全封装隔离具体实现,让外部只能通过接口来操作封装体,那么可以选用简单工厂,让客户端通过工厂来获取相应的接口,而无需关心具体实现;
- 如果想要把对外创建对象的职责集中管理和控制,可以选用简单工厂,一个简单工厂可以创建很多的、不相关的对象,可以把对外创建对象的职责集中到一个简单工厂来,从而实现集中管理和控制。
- 本质:
- 简单工厂的本质是:选择实现。
- 注意简单工厂的重点在选择,实现是已经做好了的。就算实现再简单,也要由具体的实现类来实现,而不是在简单工厂里面来实现。
- 简单工厂的目的在于为客户端来选择相应的实现,从而使得客户端和实现之间解耦,这样一来,具体实现发生了变化,就不用变动客户端了,这个变化会被简单工厂吸收和屏蔽掉。
- 实现简单工厂的难点就在于“如何选择”实现,前面讲到了几种传递参数的方法,那都是静态的参数,还可以实现成为动态的参数。比如:在运行期间,由工厂去读取某个内存的值,或者是去读取数据库中的值,然后根据这个值来选择具体的实现等等。
- 定义:定义一个用于创建对象的接口,让子类决定实例化哪一个类,Factory Method使一个类的实例化延迟到其子类。
- 说明:我的理解就是特定的工厂生成特定的产品,没有抽象工厂 模式中产品族的概念,具有的角色包括:创建者,工厂,产品,具体工厂,具体产品。他们之间的关系就是创建者使用工厂,工厂产对应的产品,在图解设计模式中是这样说的:用template 方法模式来构建生成实例的工厂就是工厂方法模式
- 类图
- 关键代码
- 疑问:直接new IdCard多方便啊
- 优缺点:
- 可以在不知具体实现的情况下编程:工厂方法模式可以让你在实现功能的时候,如果需要某个产品对象,只需要使用产品的接口即可,而无需关心具体的实现。选择具体实现的任务延迟到子类去完成。更容易扩展对象的新版本。工厂方法给子类提供了一个挂钩,使得扩展新的对象版本变得非常容易。比如上面示例的参数化工厂方法实现中,扩展一个新的导出Xml文件格式的实现,已有的代码都不会改变,只要新加入一个子类来提供新的工厂方法实现,然后在客户端使用这个新的子类即可。另外这里提到的挂钩,就是我们经常说的钩子方法(hook),这个会在后面讲模板方法模式的时候详细点说明。
- 具体产品对象和工厂方法的耦合性:在工厂方法模式里面,工厂方法是需要创建产品对象的,也就是需要选择具体的产品对象,并创建它们的实例,因此具体产品对象和工厂方法是耦合的。
- 本质:延迟到子类来选择实现
- 跟简单工厂的区别:
- 确实从本质上讲,它们是非常类似的,具体实现上都是在“选择实现”。但是也存在不同点,简单工厂是直接在工厂类里面进行“选择实现”;而工厂方法会把这个工作延迟到子类来实现,工厂类里面使用工厂方法的地方是依赖于抽象而不是具体的实现,从而使得系统更加灵活,具有更好的可维护性和可扩展性。
- 什么时候选择用工厂方法模式呢:
- 如果一个类需要创建某个接口的对象,但是又不知道具体的实现,这种情况可以选用工厂方法模式,把创建对象的工作延迟到子类去实现。
- 如果一个类本身就希望,由它的子类来创建所需的对象的时候,应该使用工厂方法模式。
- 跟模板模式有什么关系:这两个模式外观类似,都是有一个抽象类,然后由子类来提供一些实现,但是工厂方法模式的子类专注的是创建产品对象,而模板方法模式的子类专注的是为固定的算法骨架提供某些步骤的实现。换句话说,工厂方法模式一般来说都需要用到模板模式,通常在模板方法模式里面,使用工厂方法来创建模板方法需要的对象。
- 抽象工厂模式:(参考https://www.jianshu.com/p/e873855e88a0)
- 定义:提供一个创建一系列相关或互相依赖对象的接口,而无需指定他们具体的类。
- 说明:将关联零件组装成产品;不像工厂方法,简单工厂那样关注单个产品的创建,关注的相关的产品族,一系列的产品的创建,
- 类图
- 关键代码
- 优点:
- 分离接口和实现:客户端使用抽象工厂来创建需要的对象,而客户端根本就不知道具体的实现是谁,客户端只是面向产品的接口编程而已,也就是说,客户端从具体的产品实现中解耦。
- 使得切换产品簇变得容易:因为一个具体的工厂实现代表的是一个产品簇,客户端选用不同的工厂实现,就相当于是在切换不同的产品簇。
- 缺点:
- 这种实现有一个麻烦,就是如果在产品簇中要新增加一种产品,当抽象工厂一发生变化,所有的具体工厂实现都要发生变化,这非常的不灵活。
- 不太容易扩展新的产品:如果需要给整个产品簇添加一个新的产品,那么就需要修改抽象工厂,这样就会导致修改所有的工厂实现类。在前面提供了一个可以扩展工厂的方式来解决这个问题,但是又不够安全。如何选择,根据实际应用来权衡吧。\
- 容易造成类层次复杂:在使用抽象工厂模式的时候,如果需要选择的层次过多,那么会造成整个类层次变得复杂。
- 本质:选择产品簇的实现
- 什么时候使用抽象工厂模式:
- 如果希望一个系统独立于它的产品的创建,组合和表示的时候,换句话说,希望一个系统只是知道产品的接口,而不关心实现的时候。
- 如果一个系统要由多个产品系列中的一个来配置的时候,换句话说,就是可以动态的切换产品簇的时候。如果要强调一系列相关产品的接口,以便联合使用它们的时候。
GitHub:https://github.com/wk1995/DesignPattern