[整理] 设计模式之工厂模式
1. 静态工厂模式
这个最常见了,项目中的辅助类,TextUtil.isEmpty等,类+静态方法即可。
2. 简单工厂模式
案例:肉夹馍
最近程序员卖肉夹馍很火。
首先你得有个店:RoujiaMoStore
public class RoujiaMoStore
{
/**
* 根据传入类型卖不同的肉夹馍
*
* @param type
* @return
*/
public RouJiaMo sellRouJiaMo(String type)
{
RouJiaMo rouJiaMo = null;
if (type.equals("Suan"))
{
rouJiaMo = new SuanRouJiaMo();
} else if (type.equals("Tian"))
{
rouJiaMo = new TianRouJiaMo();
} else if (type.equals("La"))
{
rouJiaMo = new LaRouJiaMo();
}
rouJiaMo.prepare();
rouJiaMo.fire();
rouJiaMo.pack();
return rouJiaMo;
}
}
然后你得有各种风味的馍馍:
public abstract class RouJiaMo
{
protected String name;
/**
* 准备工作
*/
public void prepare()
{
System.out.println("揉面-剁肉-完成准备工作");
}
/**
* 使用你们的专用袋-包装
*/
public void pack()
{
System.out.println("肉夹馍-专用袋-包装");
}
/**
* 秘制设备-烘烤2分钟
*/
public void fire()
{
System.out.println("肉夹馍-专用设备-烘烤");
}
}
// 辣味肉夹馍
public class LaRouJiaMo extends RouJiaMo
{
public LaRouJiaMo()
{
this.name = "辣味肉夹馍";
}
}
// 酸味肉夹馍
public class SuanRouJiaMo extends RouJiaMo
{
public SuanRouJiaMo()
{
this.name = "酸味肉夹馍";
}
}
// 甜味肉夹馍
public class TianRouJiaMo extends RouJiaMo
{
public TianRouJiaMo()
{
this.name = "甜肉夹馍";
}
}
现在这样的设计,虽然可以支持你卖肉夹馍了,但是有点问题,生产馍的种类和你的RoujiaMoStore耦合度太高了,如果增加几种风味,删除几种风味,你得一直修改sellRouJiaMo中的方法,所以我们需要做一定的修改,此时简单工厂模式就能派上用场了。
我们开始写个简单工厂,把产生馍的过程拿出来:
public class SimpleRouJiaMoFactroy
{
public RouJiaMo createRouJiaMo(String type)
{
RouJiaMo rouJiaMo = null;
if (type.equals("Suan"))
{
rouJiaMo = new SuanRouJiaMo();
} else if (type.equals("Tian"))
{
rouJiaMo = new TianRouJiaMo();
} else if (type.equals("La"))
{
rouJiaMo = new LaRouJiaMo();
}
return rouJiaMo;
}
}
然后以组合的方式,让Store来使用:
public class RoujiaMoStore
{
private SimpleRouJiaMoFactroy factroy;
public RoujiaMoStore(SimpleRouJiaMoFactroy factroy)
{
this.factroy = factroy;
}
/**
* 根据传入类型卖不同的肉夹馍
*
* @param type
* @return
*/
public RouJiaMo sellRouJiaMo(String type)
{
RouJiaMo rouJiaMo = factroy.createRouJiaMo(type);
rouJiaMo.prepare();
rouJiaMo.fire();
rouJiaMo.pack();
return rouJiaMo;
}
}
好了,现在你随便添加什么种类的馍,删除什么种类的馍就和Store无关了,就是么人家只负责卖馍么 这就是简单工厂模式,当然了,大家也都比较熟悉。
3. 工厂方法模式
定义:定义一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法模式把类实例化的过程推迟到子类。
好了,看完定义,下面我们用例子来展示。继续肉夹馍,由于使用了简单工厂模式,肉夹馍生意那个好啊,所以下载决定去西安开个分店,去北京开个分店。既然有分店了,那总店就是抽象的了:
public abstract class RoujiaMoStore
{
public abstract RouJiaMo createRouJiaMo(String type);
/**
* 根据传入类型卖不同的肉夹馍
*
* @param type
* @return
*/
public RouJiaMo sellRouJiaMo(String type)
{
RouJiaMo rouJiaMo = createRouJiaMo(type);
rouJiaMo.prepare();
rouJiaMo.fire();
rouJiaMo.pack();
return rouJiaMo;
}
}
然后在开两个分店,这里拿一个代码做演示,其他都一样:
// 西安肉夹馍店
public class XianRouJiaMoStore extends RoujiaMoStore
{
@Override
public RouJiaMo createRouJiaMo(String type)
{
RouJiaMo rouJiaMo = null;
if (type.equals("Suan"))
{
rouJiaMo = new XianSuanRouJiaMo();
} else if (type.equals("Tian"))
{
rouJiaMo = new XianTianRouJiaMo();
} else if (type.equals("La"))
{
rouJiaMo = new XianLaRouJiaMo();
}
return rouJiaMo;
}
}
然后就是各个西安口味的肉夹馍了,这代码就不贴了。可以看出我们把制作肉夹馍的过程以抽象方法的形式让子类去决定了,对照定义:
1、定义了创建对象的一个接口:public abstract RouJiaMo createRouJiaMo(String type);
2、由子类决定实例化的类,可以看到我们的馍是子类生成的。
可能有人会说,我用简单工厂模式也行啊,但是如果10来个城市*5种风味/城市,那么岂不是简单工厂里面需要50多个if,再说人家西安肉夹馍分店就不能有点自己的秘诀,当然由它自己定最好。
好了,方法工厂模式介绍完毕。
4. 抽象工厂模式
定义:提供一个接口,用于创建相关的或依赖对象的家族,而不需要明确指定具体类。
这定义有点绕口,算了,还是拿例子来说。继续卖肉夹馍,咱们生意这么好,难免有些分店开始动歪脑子,开始使用劣质肉等,砸我们的品牌。所以我们要拿钱在每个城市建立自己的原料场,保证高质量原料的供应。
于是我们新建一个提供原料的接口:
// 提供肉夹馍的原料
public interface RouJiaMoYLFactroy
{
/**
* 生产肉
* @return
*/
public Meat createMeat();
/**
* 生产调料神马的
* @return
*/
public YuanLiao createYuanliao();
}
// 根据西安当地特色,提供这两种材料
public class XianRouJiaMoYLFactroy implements RouJiaMoYLFactroy
{
@Override
public Meat createMeat()
{
return new FreshMest();
}
@Override
public YuanLiao createYuanliao()
{
return new XianTeSeYuanliao();
}
}
有了原理工厂,那我们稍微修改下RouJiaMo的prepare方法:
public abstract class RouJiaMo
{
protected String name;
/**
* 准备工作
*/
public final void prepare(RouJiaMoYLFactroy ylFactroy)
{
Meat meat = ylFactroy.createMeat();
YuanLiao yuanliao = ylFactroy.createYuanliao();
System.out.println("使用官方的原料" + meat + " , " + yuanliao + "作为原材料制作肉夹馍 ");
}
/**
* 使用你们的专用袋-包装
*/
public final void pack()
{
System.out.println("肉夹馍-专用袋-包装");
}
/**
* 秘制设备-烘烤2分钟
*/
public final void fire()
{
System.out.println("肉夹馍-专用设备-烘烤");
}
}
好了,现在必须用我们官方原料做为原材料了。
现在对比定义:
1、提供一个接口:public interface RouJiaMoYLFactroy
2、用于创建相关的或依赖对象的家族 public Meat createMeat();public YuanLiao createYuanliao();我们接口用于创建一系列的原材料。
好了,最后测试下,我要在西安馍店,买个酸味的尝尝:
public class Test
{
public static void main(String[] args)
{
RoujiaMoStore roujiaMoStore = new XianRouJiaMoStore();
RouJiaMo suanRoujiaMo = roujiaMoStore.sellRouJiaMo("Suan");
System.out.println(suanRoujiaMo.name);
}
}
使用官方的原料com...FreshMest@e53108 , com...XianTeSeYuanliao@f62373作为原材料制作肉夹馍
肉夹馍-专用设备-烘烤
肉夹馍-专用袋-包装
酸味肉夹馍
哈哈~肉夹馍店的已经建立起来了