工厂模式是创建型模式中一种比较常用的设计模式。他用工厂方法代替用户进行new操作,大大减少了new操作产生的时间消耗。工厂模式在很多框架或是网站中大量运用,是一种不得不掌握的设计模式。
小洪的故事
今日出演:小洪、强哥
话说今天放学的档口,强哥又拍了拍小洪的肩膀。转头看见强哥,小洪不禁倒吸了一口凉气。
“强哥别找我去吃烤肉了,上次我吃完那顿回到宿舍上吐下泻的,顶不住啊!”
“老弟啊,这次我们不去吃烤肉了,上次我被女朋友教训得那叫一个惨!今天我们下馆子吃几个菜吧!”强哥说道。
“外面有一家中华茶楼不错,今天好像有活动打折呢!”小洪再一次动心了。
“那就走嘞!”
简单工厂
“你知道吗,像茶楼、菜馆这些,都是遵循着工厂模式进行营业的哦。”在公交上,强哥又开启了他的学霸模式。
“哦?那是怎么样的呢?”
public class Restruant {
public static Food makeFood(String food){
if(food.equals("拉面")){
Food food1 = new Noodle();
return food1;
}else if(food.equals("饺子")){
Food food1 = new Dumping();
return food1;
}else{
return null;
}
}
}
上面就是一个餐馆类,客户端只需要将想要的食物传进去,就可以不通过 new 关键字来创建对象了,客户端想要调用就通过以下的方式进行调用。
public class People {
public static void main(String[] args) {
Restruant.makeFood("饺子").name();
Restruant.makeFood("拉面").name();
}
}
“这样你在想要吃饺子的时候,就不需要进行 new,也不需要关注饺子实现的细节。“
“哇,也太下饭了这知识,我待会就决定吃饺子了!”
“你关注点倒是离谱得很。”
工厂方法
小洪和强哥终于抵达了中华茶楼,他俩找了个靠窗的位置坐下来。
“今天我要学以致用,且看我如何用简单工厂点一份新鲜的饺子!”小洪看到菜单,看似所向披靡。
“哎!老弟啊,你不会举一反三啊,你想想,如果你现在想吃牛肉水饺怎么办?”
“啊?那就在工厂中加入牛肉水饺啊。就像这样”
public class Restruant {
public static Food makeFood(String food){
if(food.equals("拉面")){
Food food1 = new Noodle();
return food1;
}else if(food.equals("饺子")){
Food food1 = new Dumping();
return food1;
}else if(food.equals("牛肉水饺")){
Food food1 = new BeefDumping();
return food1;
}else{
return null;
}
}
}
“那如果我想吃羊肉水饺呢?也要往里面继续加,如果以后我需要更多的需求呢,你会发现这个工厂类将变得很大,而且难以维护,用软件工程导论里的话,叫做耦合度太高了。”
“那怎么办?”
“其实像中华茶楼这么大的招牌,肯定不止一个厨房,他们的厨房是有分工的,一个厨房做饺子,一个厨房做拉面,将一个工厂变成两个或多个工厂。这样他们的管理和维护将会更简单。简单工厂的解决方法也是这样的。”
“我知道了,像下面这样表示。”
public interface Restruant {
Food makeFood(String name);
}
public class DumpingFactory implements Restruant {
@Override
public Food makeFood(String food){
if(food.equals("牛肉饺子")){
Food food1 = new BeefDumping();
return food1;
}else if(food.equals("鸡肉饺子")){
Food food1 = new ChickenDumping();
return food1;
}else{
return null;
}
}
}
public class NoodleFactory implements Restruant {
@Override
public Food makeFood(String food){
if(food.equals("牛肉拉面")){
Food food1 = new BeefNoodle();
return food1;
}else if(food.equals("鸡肉拉面")){
Food food1 = new ChickenNoodle();
return food1;
}else{
return null;
}
}
}
“是的,这就是工厂方法,在需要多个类别或是多个工厂的时候进行使用。”强哥点点头,看来小洪还是有举一反三的能力的。
抽象工厂
酒足饭饱,茶足饭饱之后,小洪和强哥走出茶楼,准备在街上散散步。
“强哥,你看那边,还有一家 [中华酒楼] 。”小洪指着远处。
“哦豁,这又涉及抽象工厂模式了。”强哥又开始了。
“抽象工厂是啥?“
“抽象工厂里有一个产品族的概念,就比如:中华茶楼里的拉面和饺子是同一个产品族,而中华酒楼的拉面和饺子属于一个产品族。”
“理解,但是这跟抽象工厂有什么关系吗?”
“来看一下我画的类图就知道了。”
现在我们已经不定义什么饺子工厂、拉面工厂这些产品工厂了。我们直接将整个餐馆定义为工厂,每个工厂负责整个产品族的生产。而他们都实现了餐馆的接口,但是餐馆这个总接口是干嘛的我们也不需要管。
public interface Restruant {
Dumping makeDumping();
Noodle makeNoodle();
}
public class ChaLou implements Restruant {
@Override
public Dumping makeDumping() {
return new ChaLouDumping();
}
@Override
public Noodle makeNoodle() {
return new ChaLouNoodle();
}
}
public class JiuLou implements Restruant {
@Override
public Dumping makeDumping() {
return new JiuLouDumping();
}
@Override
public Noodle makeNoodle() {
return new JiuLouNoodle();
}
}
客户端想要调用的话,需要新建一个自己想要的工厂,然后用这个工厂去实现你想要吃的各种食物。如下所示:
public class People {
public static void main(String[] args) {
Restruant chalou = new ChaLou();
chalou.makeDumping().name();
chalou.makeNoodle().name();
}
}
运行结果为:
中华茶楼的饺子
中华茶楼的拉面
“但这样,每次新增一种食物不就会很难?比如中华茶楼想新增汤圆这种食物,就实现汤圆接口、还要在总接口 Restruant 上新增汤圆的方法,最后再在自己的工厂类中实现自己的方法。”
“对,这就是抽象工厂模式的弊端,如果想要加一种产品,就需要修改所有工厂,在扩展上极为不便。”
“这样啊,那老哥这顿饭怎么还是你请啊?”小洪的注意力还是不能坚持三秒。
“没事,这家好吃,而且也不贵,明天就带女朋友来这里吃了。”
“可是明天就没有打折了呀!”