简介
工厂模式解决的是频繁的修改某一些 new 操作,隐藏真实的创建过程,方便以后更加快速的新增和扩展,简单来说就是维护一类关系。
简单工厂:
把对象的创建放到一个Util中,通过不同的入参来创建不同的类。这也是日常编码中经常用到的,不过缺点就是每次新增一个类的时候,都需要修改if/else
判断,有点繁琐。
工厂方法:
将含有相同属性的类抽象成一个工厂,这一个工厂只负责自己的对象的创建,对修改关闭,对扩展开放。
抽象工厂:
对类的操作进一步的划分,将某种类的操作再次进行抽象化。
代码
假设现在要开发一个餐厅点餐系统,首先肯定是有顾客以及食物。为了以后的扩展性,在这里通过三种工厂方法来实现不同的需求
简单工厂
现在有两个类,User 和 Food,此时有一个需求是人需要吃食物,可能你毫不犹豫的写下了如下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| public class Potato { private int temperaturel;
private String name;
public Potato(String name) { this.name = name; }
public void cook(){ System.out.println("加热中"); this.temperaturel = 100; }
public String getName() { return name; }
public void setName(String name) { this.name = name; } }
public class User { public static void main(String[] args) { new User().dinner(); }
private void dinner(){ Potato potato = new Potato("土豆"); potato.cook(); System.out.println("吃晚餐" + potato.getName()); } }
|
后来有一天需求变了,现在需要再加一个食物以供客户选择,后来你想了下,决定写一个 Util
类。如下:
1 2 3 4 5 6 7 8 9
| public static Object getFood(String name){ if(name != null){ if("Potato".equals(name)){ return new Potato("土豆"); } else if("Tomato".equals(name)){ return new Tomato("西红柿"); } } }
|
这段代码明显的有一个问题就是,返回的 Object 在另一个地方进行强制转换的时候,由于不知道返回的是 Potato 还是 Tomato,所以很容易抛出转换异常,所以此时,再继续优化这段代码,由于土豆和西红柿都是食物的一种,于是可以直接抽象一个接口出来。这样土豆和马铃薯都实现这个接口。如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| public interface Food {
void cook();
String getName(); } public class Potato implements Food{ private int temperaturel;
private String name;
public Potato(String name) { this.name = name; }
@Override public void cook(){ System.out.println("加热中"); this.temperaturel = 100; }
@Override public String getName() { return name; }
public void setName(String name) { this.name = name; } } public class Tomato implements Food{ private int temperaturel;
private String name;
public Tomato(String name) { this.name = name; }
@Override public void cook(){ System.out.println("加热中"); this.temperaturel = 100; }
@Override public String getName() { return name; }
public void setName(String name) { this.name = name; } }
|
这个时候呢,修改 Util 类,让它返回 Food 这个抽象,然后通过实例化子类,来实现模版的调用,于是继续修改 Util 类。如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| public class FoodUtil { public static Food getFood(String name){ if(name != null){ if("Potato".equals(name)){ return new Potato("土豆"); } else if("Tomato".equals(name)){ return new Tomato("西红柿"); } } return null; } }
public class User { public static void main(String[] args) { new User().dinner("Potato"); new User().dinner("Tomato"); }
private void dinner(String name){ Food food = FoodUtil.getFood(name); food.cook(); System.out.println("吃晚餐" + food.getName()); } }
|
但是随着食物种类的不断增加,每一次新增一种食物,你都要去修改getFood
这个方法,每次修改完毕之后,你还必须对其进行回归测试,万一改错了,或者equals
方法调用者的key
重复了,那就会影响到系统的运行了。而且这也不符合设计模式里面的开闭原则,对扩展开放,对修改关闭。所以此时继续对这个 Util 进行修改。
1 2 3 4 5 6 7
| public static Food getFood(Class<? extends Food> clazz) throws IllegalAccessException, InstantiationException { if(clazz != null){ return clazz.newInstance(); } return null; }
|
这就是一个简单工厂模式,简单工厂模式严格意义上来讲并不属于设计模式其中之一,但是这也是我们在开发过程中经常使用的一种方式,用于避免一些无意义的 new 操作。
接下来就来讲下工厂方法模式。
工厂方法模式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public interface FoodFactory { Food createFood(); }
public class PotatoFactory implements FoodFactory { @Override public Food createFood() { return new Potato(); } }
public class TomatoFactory implements FoodFactory { @Override public Food createFood() { System.out.println("清洗干净"); System.out.println("切好"); return new Tomato(); } }
|
这个时候,假设我们要使用的话,则直接通过 new 一个子类即可,如下代码:
1 2 3 4 5 6 7 8
| public class User { public static void main(String[] args) { FoodFactory potatoFactory = new PotatoFactory(); FoodFactory tomatoFactory = new TomatoFactory(); tomatoFactory.createFood().cook(); potatoFactory.createFood().cook(); } }
|
这样做的好处是,对扩展开放,当需要添加其他食物的时候,直接新建一个Factory
类然后实现FoodFactory
接口即可,这就是工厂模式的好处。
抽象工厂模式
抽象工厂模式是对工厂的更进一步抽象,例如 土豆 和 西红柿是一组产品,因为它们都同属于食物。但是现在有两个地方都可以生产 土豆 和 西红柿,A地的是金色的,B地生产的是银色的,于是此时 A 和 B 就产生了一个产品等级。但是A 和 B都是具有一组通用的特性,即使可以生产不同的颜色 土豆 和 西红柿。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| public interface PlantFactory { Tomato plantTomato();
Potato plantPotato(); }
public class AFactory implements PlantFactory{ @Override public Tomato plantTomato() { System.out.println("plantTomato By A"); return new Tomato(); }
@Override public Potato plantPotato() { System.out.println("plantPotato By A"); return new Potato(); } }
public class BFactory implements PlantFactory { @Override public Tomato plantTomato() { System.out.println("plantTomato By B"); return new Tomato(); }
@Override public Potato plantPotato() { System.out.println("plantPotato By B"); return new Potato(); } }
public class User { public static void main(String[] args) { PlantFactory plantFactory = new AFactory(); plantFactory.plantPotato().cook(); } }
|
总的来说,这三种设计模式中,除了抽象工厂模式很少使用到,其他两种在平常开发的项目中基本上都可以看到。