概述 平时构建对象最常用方法是new一个对象,这属于一种硬编码。每当new一个对象,调用者就会多知道一个类,类与类之间的耦合度增加。我们可以把构建过程封装起来,工厂模式就是用于封装对象的设计模式
简单工厂模式
通常我们new一个对象我们需要某一个具体的对象的构造方法,相当于我们需要一个苹果,需要知道苹果的构造方法,需要栗子,就需要知道栗子的构造方法。
更好的实现方法是有一个水果工厂,我们只需要告知需要什么具体的水果,水果工厂将需要的水果制造出来给我们就可以。整个过程只用和水果工厂打交道。
#水果工厂 public class FruitFactory { public Fruit create (String type) { switch (type){ case "苹果" : return new Apple (); case "梨子" : return new Pear (); default : throw new IllegalArgumentException ("暂时没有这种水果" ); } } } #调用者 public class User { private void eat () { FruitFactory fruitFactory = new FruitFactory (); Fruit apple = fruitFactory.create("苹果" ); Fruit pear = fruitFactory.create("梨子" ); apple.eat(); pear.eat(); } }
事实上,将构建过程封装的好处不仅可以降低耦合,如果某个产品构造方法相当复杂,使用工厂模式可以大大减少代码重复。比如,如果生产一个苹果需要苹果种子、阳光、水分,将工厂修改如下:
public class FruitFactory { public Fruit create (String type) { switch (type) { case "苹果" : AppleSeed appleSeed = new AppleSeed (); Sunlight sunlight = new Sunlight (); Water water = new Water (); return new Apple (appleSeed, sunlight, water); case "梨子" : return new Pear (); default : throw new IllegalArgumentException ("暂时没有这种水果" ); } } }
调用者的代码则完全不需要变化,而且调用者不需要在每次需要苹果时,自己去构建苹果种子、阳光、水分以获得苹果。苹果的生产过程再复杂,也只是工厂的事。这就是封装的好处,假如某天科学家发明了让苹果更香甜的肥料,要加入苹果的生产过程中的话,也只需要在工厂中修改,调用者完全不用关心。
工厂模式一共有三种:
简单工厂模式
工厂方法模式
抽象工厂模式
注:在 GoF 所著的《设计模式》一书中,简单工厂模式被划分为工厂方法模式的一种特例,没有单独被列出来。
总而言之,简单工厂模式就是让一个工厂类承担构建所有对象的职责。调用者需要什么产品,让工厂生产出来即可。它的弊端也显而易见:
一是如果需要生产的产品过多,此模式会导致工厂类过于庞大,承担过多的职责,变成超级类。当苹果生产过程需要修改时,要来修改此工厂。梨子生产过程需要修改时,也要来修改此工厂。也就是说这个类不止一个引起修改的原因。违背了单一职责原则。
二是当要生产新的产品时,必须在工厂类中添加新的分支。而开闭原则告诉我们:类应该对修改封闭。我们希望在添加新功能时,只需增加新的类,而不是修改既有的类,所以这就违背了开闭原则。
工厂方法模式 为了解决简单工厂模式的这两个弊端-单一职责原则和开闭原则,工厂方法模式应运而生,它规定每个产品都有一个专属工厂。比如苹果有专属的苹果工厂,梨子有专属的梨子工厂。
#苹果工厂 public class AppleFactory { public Fruit create () { return new Apple (); } } #橘子工厂 public class PearFactory { public Fruit create () { return new Pear (); } } #调用者 public class User { private void eat () { AppleFactory appleFactory = new AppleFactory (); Fruit apple = appleFactory.create(); PearFactory pearFactory = new PearFactory (); Fruit pear = pearFactory.create(); apple.eat(); pear.eat(); } }
用简单工厂模式,我们只需要知道 FruitFactory,无需知道 Apple 、Pear 类,很容易看出耦合度降低了。但用工厂方法模式,调用者虽然不需要和 Apple 、Pear 类打交道了,但却需要和 AppleFactory、PearFactory 类打交道。有几种水果就需要知道几个工厂类,耦合度完全没有下降啊,甚至还增加了代码量!
仔细想一想,工厂模式的第二个优点在工厂方法模式中还是存在的。当构建过程相当复杂时,工厂将构建过程封装起来,调用者可以很方便的直接使用,同样以苹果生产为例:
public class AppleFactory { public Fruit create () { AppleSeed appleSeed = new AppleSeed (); Sunlight sunlight = new Sunlight (); Water water = new Water (); return new Apple (appleSeed, sunlight, water); } }
调用者无需知道苹果的生产细节,当生产过程需要修改时也无需更改调用端。同时,工厂方法模式解决了简单工厂模式的两个弊端。
当生产的产品种类越来越多时,工厂类不会变成超级类。工厂类会越来越多,保持灵活。不会越来越大、变得臃肿。如果苹果的生产过程需要修改时,只需修改苹果工厂。梨子的生产过程需要修改时,只需修改梨子工厂。符合单一职责原则。 当需要生产新的产品时,无需更改既有的工厂,只需要添加新的工厂即可。保持了面向对象的可扩展性,符合开闭原则。
完整例子 #口罩超类 abstract class Mask {} public class SurgicalMask extends Mask { @NonNull @Override public String toString () { return "这是医用口罩" ; } } public class N95Mask extends Mask { @NonNull @Override public String toString () { return "这是 N95 口罩" ; } }
#简单工厂模式 public class MaskFactory { public Mask create (String type) { switch (type){ case "Surgical" : return new SurgicalMask (); case "N95" : return new N95Mask (); default : throw new IllegalArgumentException ("Unsupported mask type" ); } } } # 工厂模式 public class SurgicalMaskFactory { public Mask create () { return new SurgicalMask (); } } public class N95MaskFactory { public Mask create () { return new N95Mask (); } }