浅谈工厂设计模式--本次试验将工厂模式分为三个层次(简单工厂模式、复杂工厂模式、抽象工厂模式),并各自讲解联系,由浅到深。
工厂模式出现的情况类似如下情况:
现有类A、B、C、D,D中有方法d
此后分别在A、B、C中实例化D对象并调用d()方法
此时考虑如下情况:如果出现功能类似D的类E,并打算用E的e()取代d()方法,那么我们就需要在A、B、C、中分别修改D对象和d()方法为E对象和e()方法,这将是是非常麻烦的事情,甚至有更多的类调用了D的d()方法。
假设场景:有一个Person(人),他有一个吃鱼的方法eatFish(),那么在每次他吃鱼之前我们都要为他提供一条鱼。
鱼(Fish)有2种,分别为红鱼(RedFish)和黑鱼(DarkFish),每条鱼都有一个String name属性和getName()方法。
Person在吃鱼时,都会输出吃的鱼的名称。
思考:如果我们在Person的eatFish()中直接 RedFish redFish = new RedFish();,那么当我们打算将红鱼换成黑鱼的时候就会出现之前所讨论的情况。
现在我们先来看简单工厂设计模式:
因为Person吃鱼主要是调用鱼的getName()得到鱼的name,所有我们将所有的鱼的getName()方法抽象为一个接口方法,将鱼抽象为一个接口类,而红鱼、黑鱼等鱼都实现了鱼(Fish)这个接口。
interface Fish{
String getName() ;
}
class RedFish implements Fish {
@Override
public String getName() {return "红鱼";}
}
class DarkFish implements Fish {
@Override
public String getName() {return "黑鱼";}
}
之后,我们来定义Person类:
class Person {
public void eatFish() {}
}
至此,我们要开始定义我们的工厂类了,我们打算通过工厂类来调用不通的鱼返回给Person对象,那么我们需要在Person中定义一个Fish对象的引用,用来接收工厂返回的鱼的对象,这里我们就用Fish fish这个引用来接收(因为所有的鱼都实现了Fish接口,相当是Fish的子类,所以这里是父类引用指向子类对象,这是java的多态性)。
此后,我们开始定义我们的Factory,并提供static Fish getFishName ()方法:
class FishFactory{
public static Fish getFishName() {return null; }
}
到这里,最基本的对象我们已经分析、定义完毕,接下来我们开始来组合它们:
因为人要吃鱼,首先要获得鱼这个对象,所以我们要先通过FishFactory返回我们的鱼,修改如下:
class FishFactory{
public static Fish getFishName() {
Fish fish = new DarkFish();
return fish;
}
}
class Person {
private Fish fish = null;
public void eatFish() {
fish = FishFactory.getFishName();
System.out.println("我吃的是"+fish.getName());
}
}
如此修改后,当人吃鱼的时候就可以通过修改FishFactory中的Fish对象来控制人吃的鱼的种类,也就避免了在人吃鱼的时候多出修改不同鱼的对象。
至此,人吃鱼这个简单工厂设计模式讲述完毕。
总结:上述简单工厂模式降低了类之间的耦合度,但任然存在不足的地方,因为当我们要更换不同的鱼的种类的时候,我们都要在工厂类中修改,而且每次只能提供一种鱼,这是非常不现实的。
图示:
现在我们来看复杂工厂设计模式:
在简单工厂模式的基础上,我们发现:每次吃鱼都只能返回一种,如果是我同的Person想要吃不同的鱼,那么就没法满足了,所以我们在简单工厂设计模式的基础上做出修改:
我们分别为不同的鱼提供不同的工厂类,但是这些工厂类都必须实现相同的接口类,且这个工厂接口类,必须提供一个返回生产具体鱼的工厂类。
方案:
将FishFactory抽象为一个接口,包含方法:productFish ()放回具体鱼对象
定义两个工厂类(RedFishFactory、DarkFishFactory),并实现接口FishFactory
interface FishFactory{
public Fish productFish() ;
}
class DarkFishFactory implements FishFactory{
@Override
public Fish productFish() {
return new DarkFish();
}
}
class RedFishFactory implements FishFactory{
@Override
public Fish productFish() {
return new RedFish();
}
}
此时,在对人吃鱼进行下述修改:
class Person {
private FishFactory fishFactory = null;
public void eatFish() {
fishFactory = new DarkFishFactory();//也可以使RedFishFactory
System.out.println("我吃的是"+fishFactory.productFish().getName());
}
}
可能有读者认为在人吃鱼的时候每个地方都要fishFactory = new DarkFishFactory();,不是和我们最上面讨论的一样,如果工厂改了不就要到处改了吗?那么我想说的是:我们每次生产的对象是鱼,所以我们最多也就是在不同的工厂上更换上不同的鱼,而不是去更换对应的工厂。
虽然如此,但是这还是显现了对象和程序的耦合性,所以,我们将在下面进一步的降低他们的耦合度。
最后是抽象工厂设计模式:我们也是基于复杂工厂设计模式,其实只要稍稍改下也就差不多了。
方案:
我们添加一个返回工厂的类ProductFactory,并提供一个静态方法:getFactoryInstance(),代码如下:
class ProductFactory{
public static FishFactory getFactoryInstance(String factoryType) {
if(factoryType.equals("黑鱼")) {
return new DarkFishFactory();
}else if(factoryType.equals("红鱼")) {
return new RedFishFactory();
}
return null;
}
}
此外,修改人吃鱼的方法:
class Person {
private FishFactory fishFactory = null;
public void eatFish() {
fishFactory = ProductFactory.getFactoryInstance("红鱼");
System.out.println("我吃的是"+fishFactory.productFish().getName());
}
}
综上,我们已经完成了抽象工厂模式的设计,当我们需要修改返回的鱼的类型的时候,我们只要修改对应的String factoryType参数就行了。