Hi~又见面啦,从这篇开始我们就要进入正题啦,每篇讲一类设计模式,快来共同进步吧~
一、简单工厂模式:
概念:
简单工厂模式是属于创建型模式,又叫做静态工厂方法(Static Factory Method)模式,但不属于23种GOF设计模式之一。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式,可以理解为是不同工厂模式的一个特殊实现。
举个列子:
我是一个吃货,爱吃罐头,需求比较麻烦想吃各种各样的罐头,比如:有时候,我要吃草莓味的罐头,有时,我要桃味的罐头,有时,我又想吃山楂味的罐头;而恰巧古时候的罐头厂长思想比较落后,他们只懂得生产一种味道的罐头,(草莓罐头厂只生产草莓味儿的,桃罐头厂只生产黄桃味儿的,山楂罐头场只生产山楂味的);这样我想吃某一种口味的罐头就得去跑到对应的厂去买。
模式的问题:
你如何能轻松方便地构造对象实例,而不必关心构造对象实例的细节和复杂过程呢?
原始时代:消费者要关心每个类的实现细节。
角色:产品、消费者
产品:
/**
* Created by Sunrui on 2017/5/11.
* 山楂味罐头实体类
*/
public class CanHawthorn {
private String taste;
public CanHawthorn (String taste){
this.taste = taste;
}
public String tell(){
return this.taste;
}
}
/**
* Created by Sunrui on 2017/5/11.
* 桃味罐头实体类
*/
public class CanPeach {
private String taste;
public CanPeach (String taste){
this.taste = taste;
}
public String getTaste(){
return this.taste;
}
}
/**
* Created by Sunrui on 2017/5/11.
* 草莓罐头实体类
*/
public class CanStrawberry {
private String taste;
public CanStrawberry (String taste){
this.taste = taste;
}
public String say(){
return this.taste;
}
}
消费者:
/**
* Created by Sunrui on 2017/5/11.
* 消费者
*/
public class ConsumerWithoutFactory {
public static void main(String[] args){
CanHawthorn canHawthorn = new CanHawthorn("山楂");
CanPeach canPeach = new CanPeach("桃");
CanStrawberry canStrawberry = new CanStrawberry("草莓");
System.out.println("吃到口味:" + canHawthorn.tell() + "、" +
canPeach.getTaste() + "、 " + canStrawberry.say());
}
}
在还没有工厂的时代:
我们创建每个对象需要很大的代价,消费者需要直接跟具体的类关联。并且要关心具体类的内部实现细节(这里用通知方法(tell,say,getTaste)代表每个类的内部细节)
-----------------------------------------划时代的分割线-------------------------------------------
时代在发展,社会在进步,我们进入简单工厂时代~
简单工厂时代:消费者只需面对工厂,具体实现细节由工厂去跟每个类打交道
角色:
工厂:为消费者得到产品的媒介
产品父类:抽象类将产品中共有的功能抽象出来,定义共有的产品规范
产品:具体的产品
消费者:略
工厂:
/**
* Created by sunrui on 2017/5/11.
*/
public class CanFactory {
public Can createCan(char name){
switch (name){
case 'h':
return new CanHawthorn("山楂");
case 'p':
return new CanPeach("桃");
case 's':
return new CanStrawberry("草莓");
default:
break;
}
return null;
}
}
抽象父类:
/**
* Created by Sunrui on 2017/5/11.
* 抽象产品父类
*/
public abstract class Can {
public Can (){
}
/**
* 定义产品共有的行为
*/
public abstract String speak();
}
产品:继承父类,按照父类的规范来定义行为
/**
* Created by Sunrui on 2017/5/11.
* 山楂味罐头实体类
*/
public class CanHawthorn extends Can{
private String taste;
public CanHawthorn (String taste){
this.taste = taste;
}
public String speak(){
return this.taste;
}
}
/**
* Created by Sunrui on 2017/5/11.
* 桃味罐头实体类
*/
public class CanPeach extends Can{
private String taste = "桃味";
public CanPeach (String taste){
this.taste = taste;
}
public String speak(){
return this.taste;
}
}
/**
* Created by Sunrui on 2017/5/11.
* 草莓罐头实体类
*/
public class CanStrawberry extends Can{
private String taste;
public CanStrawberry (String taste){
this.taste = taste;
}
public String speak(){
return this.taste;
}
}
消费者:
/**
* Created by Sunrui on 2017/5/11.
* 消费者
*/
public class ConsumerWithSimpleFactory {
public static void main(String[] args){
CanFactory canFactory = new CanFactory();
Can canHawthorn = canFactory.createCan('h');
Can canPeach = canFactory.createCan('p');
Can canStrawberry= canFactory.createCan('s');
System.out.println("吃到口味:" + canHawthorn.speak() + "、" +
canPeach.speak() + "、 " + canStrawberry.speak());
}
}
一点理解:
以上是简单工厂模式的几个角色,那么简单工厂模式到底做了那些事情呢?
1、定义抽象产品父类:定义,规范了产品共有的属性和方法(细心地你可以发现子类中之前的tell,getTaste,say其实都是抽象起来都是相同的方法,定衣父类后统一定义为speak),方便消费者调用
2、创建了工厂概念:屏蔽了具体产品子类的实现细节,架接起消费者与产品之间的沟通桥梁,我们把它理解为一个模子,根据外界给定的原料,在加上自身封装好的判断,生产出不同类型的相应的产品、对象。(网上某篇文章的理解感觉很不错在这引用一下)
3、对于消费者:只需要创建工厂,与工厂打交道,告诉工厂你需要的产品,让工厂来生产对象,而不需要直接面向你所需要的产品。
但同时简单工厂模式也有一些弊端:假如现在生产线更发达了,多了一中橘子味罐头,那我们势必要修改(注意是修改!与接下来的工厂方法模式在这里有实质性的区别)罐头工厂中的createCan()方法,读过前一篇设计模式六大原则的朋友一定会想到,这里就违反了设计模式中的开放封闭原则(实体应该尽量做到可扩展,不可修改),但是相较于没有工厂的模式,简单工厂模式已经迈出了一大步。
为了解决这个弊端,接下来,我们进入到工厂方法模式的学习@A@
-----------------------------------------划时代的分割线-------------------------------------------
二、工厂方法模式:
概念:
工厂方法模式(FACTORY METHOD)是一种常用的对象创建型设计模式,此模式的核心精神是封装类中不变的部分,提取其中个性化善变的部分为独立类,通过依赖注入以达到解耦、复用和方便后期维护拓展的目的。它的核心结构有四个角色,分别是抽象工厂;具体工厂;抽象产品;具体产品。
与简单工厂模式的差别:
工厂方法模式比简单工厂模式多了一个概念即抽象工厂。
角色:
抽象工厂:抽象工厂类不再负责产品的创建,这样核心类成为一个抽象工厂角色,仅负责具体工厂子类必须实现的接口。(形似于产品和产品父类的关系)
具体工厂:为消费者得到产品的媒介,生产产品的具体实体。
产品父类:抽象类将产品中共有的功能抽象出来,定义共有的产品规范
产品:具体的产品
消费者:略
抽象工厂:
/**
* Created by Sunrui on 2017/5/11.
* 抽象工厂,用来定义工厂规范
*/
public interface CanFactory {
Can createCan();
}
具体工厂:
/**
* Created by Sunrui
* Create Date: 2017/5/11
* Description: 山楂罐头的实体工厂
*/
public class HawthornCanFactory implements CanFactory{
/**
* 创建山楂罐头
* @return CanHawthorn
*/
public CanHawthorn createCan(){
return new CanHawthorn("山楂");
}
}
/**
* Created by Sunrui
* Create Date: 2017/5/11
* Description: 桃罐头的实体工厂
*/
public class PeachCanFactory implements CanFactory{
/**
* 创建桃罐头实体
*/
public CanPeach createCan(){
return new CanPeach("桃味");
}
}
/**
* Created by Sunrui
* Create Date: 2017/5/11
* Description: 草莓罐头的实体工厂
*/
public class StrawberryCanFactory implements CanFactory{
/**
* 创建草莓罐头实体
*/
public CanStrawberry createCan(){
return new CanStrawberry("草莓味");
}
}
产品父类:
/**
* Created by Sunrui on 2017/5/11.
* 抽象产品父类
*/
public abstract class Can {
public Can (){
}
/**
* 定义产品共有的行为
*/
public abstract String speak();
}
产品:
/**
* Created by Sunrui on 2017/5/11.
* 山楂味罐头实体类
*/
public class CanHawthorn extends Can {
private String taste;
public CanHawthorn (String taste){
this.taste = taste;
}
public String speak(){
return this.taste;
}
}
/**
* Created by Sunrui on 2017/5/11.
* 桃味罐头实体类
*/
public class CanPeach extends Can {
private String taste = "桃味";
public CanPeach (String taste){
this.taste = taste;
}
public String speak(){
return this.taste;
}
}
/**
* Created by Sunrui on 2017/5/11.
* 草莓罐头实体类
*/
public class CanStrawberry extends Can {
private String taste;
public CanStrawberry (String taste){
this.taste = taste;
}
public String speak(){
return this.taste;
}
}
消费者:
/**
* Created by Sunrui on 2017/5/11.
* 消费者
*/
public class ConsumerWithSimpleFactory {
public static void main(String[] args){
//创建的具体的工厂
CanFactory strawberryCanFactory = new StrawberryCanFactory();
CanFactory hawthornCanFactory = new HawthornCanFactory();
CanFactory peachCanFactory = new PeachCanFactory();
//创建不通口味的产品
Can strawberryCan = strawberryCanFactory.createCan();
Can hawthornCan = hawthornCanFactory.createCan();
Can peachCan = peachCanFactory.createCan();
System.out.println("吃到口味:" + strawberryCan.speak() + "、" +
hawthornCan.speak() + "、 " + peachCan.speak());
}
}
怎么样?不知大家会意没?
接上个简单工厂抛出的问题,如果我们现在多了一个橘子口味的产品,我们只需增加一个抽象工厂类,(注意只是增加,避免对之前的修改),另增加一个橘子味的产品,即可通过新增加的这个抽象工厂得到相应的产品。
一点理解:
使用工厂方法后,调用端的耦合度大大降低了。并且对于工厂来说,是可以扩展的(对于这个例子,我们增加了一个口味),无论是灵活性还是稳定性都得到了极大的提高。
适用场景:
不管是简单工厂模式,工厂方法模式他们具有类似的特性,所以他们的适用场景也是类似的。
首先,作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别是只需要通过new就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。
其次,工厂模式是一种典型的解耦模式,迪米特法则在工厂模式中表现的尤为明显。假如调用者自己组装产品需要增加依赖关系时,可以考虑使用工厂模式。将会大大降低对象之间的耦合度。
再次,由于工厂模式是依靠抽象架构的,它把实例化产品的任务交由实现类完成,扩展性比较好。也就是说,当需要系统有比较好的扩展性时,可以考虑工厂模式,不同的产品用不同的实现工厂来组装。
好啦,今天的学习就到这里吧,不知各位互联网的小伙伴是否和我一样收货颇丰,相信每天进步一点点,不久之后你就会有质的改变,我们下一篇见!