一、模式定义
二、简单工厂模式
三、工厂方法模式
四、抽象工厂模式
工厂模式(Factory Pattern)是常见的设计模式之一。该模式中,我们在创建对象时不对客户端暴露创建逻辑,并且是通过使用一个公共的接口来创建新的对象,将业务逻辑与界面逻辑分离,降低耦合度。
简单工厂模式,构造不同类型对象、将对象的创建和本身的业务逻辑分离。
定义一个创建对象的接口,将对象的创建和本身的业务逻辑分离,降低系统的耦合度,使得两个修改起来相对容易些,当以后实现改变时,只需要修改工厂类即可。
应用举例:
肉厂(MeatFactory)可以生产猪肉(Pork),牛肉(Beef),鸡肉(Chicken)等肉类(Meat),使用简单工厂方法实现肉类的生产。
UML类图:
产品类
//Meat类
public interface Meat {
public String showMeat();
}
//Beef类
public class Beef implements Meat {
@Override
public String showMeat() {
return "生产牛肉中……";
}
}
//Chicken类
public class Chicken implements Meat {
@Override
public String showMeat() {
return "生产鸡肉中……";
}
}
//Pork类
public class Pork implements Meat {
@Override
public String showMeat() {
return "生产猪肉中……";
}
}
MeatFactory类
public class MeatFactory {
public static Meat getMeat (String meatType){
Meat meat = null;
switch (meatType){
case "pork" : meat = new Pork();
break;
case "beef" : meat = new Beef();
break;
case "chicken" : meat = new Chicken();
break;
default:
System.out.println("ERROR");
break;
}
return meat;
}
}
测试类
public class Demo {
public static void main(String[] args) {
Meat meat = MeatFactory.getMeat("pork");
System.out.println(meat.showMeat());
}
}
优点:
工厂类含有必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端可以免除直接创建产品对象的责任,而仅仅“消费”产品;简单工厂模式通过这种做法实现了对责任的分割,它提供了专门的工厂类用于创建对象。
缺点:
我们要在这个简单工厂类里编写很多个方法,每个方法里都得写很多相应的业务代码,而每次增加子类或者删除子类对象的创建都需要打开这简单工厂类来进行修改。这会导致这个简单工厂类很庞大臃肿、耦合性高,而且增加、删除某个子类对象的创建都需要打开简单工厂类来进行修改代码也违反了开-闭原则。
工厂方法模式(Factory Method),定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使得一个类的实例化延迟到其子类。
应用举例
肉厂(MeatFactory)可以生产猪肉(Pork),牛肉(Beef),鸡肉(Chicken)等肉类(Meat),使用简单工厂方法实现肉类的生产。
UML类图
产品类
/*Meat类*/
public interface Meat {
public String showMeat();
}
/*Beef类*/
public class Beef implements Meat {
@Override
public String showMeat() {
return "生产牛肉中……";
}
}
/*Chicken类*/
public class Chicken implements Meat {
@Override
public String showMeat() {
return "生产鸡肉中……";
}
}
/*Pork类*/
public class Pork implements Meat {
@Override
public String showMeat() {
return "生产猪肉中……";
}
}
工厂类
MeatFactory类
public abstract class MeatFactory {
public abstract Meat getMeat();
}
BeefFactory类
/*BeefFactory类*/
public class BeefFactory extends MeatFactory {
@Override
public Meat getMeat() {
return new Beef();
}
}
/*ChickenFactory类*/
public class ChickenFactory extends MeatFactory {
@Override
public Meat getMeat() {
return new Chicken();
}
}
/*PorkFactory类*/
public class PorkFactory extends MeatFactory {
@Override
public Meat getMeat() {
return new Pork();
}
}
测试类
public class Demo {
public static void main(String[] args) {
MeatFactory factory=new BeefFactory();
System.out.println(factory.getMeat().showMeat());
}
}
工厂方法模式对比简单工厂模式:
工厂方法模式和简单工厂的区别在于,简单工厂模式的最大优点在于工厂类中包含了必要的逻辑判断,根据客户端的选择条件动态实例化相关的类,对子客户端来说,去了与具体产品的赖。就像你的猪肉产品,让客户端不用管该用哪个类的实例,只需要把‘pork’给工厂,工厂自动就给出了相应的实例,客户端只要去做运算就可以了,不同的实例会生产不同的产品。但问题也就在这里,如你所说,如果要添加其他肉类产品,我们是一定需要给肉类工厂类的方法里加Case的分支条件的,修改原有的类?这可不是好办法,这就等于说,我们不但对扩展开放了,对修改也开放了,这样就违背开放封闭原则。
其实你仔细观察就会发现,工厂方法模式实现时,客户端需要决定实例化哪一个工厂来实现类,选择判断的问题还是存在的,也就是说,工厂方法把简单工厂的内部逻辑判断移到了客户端进行,你想要加功能,本来是改工厂类的,而现在是修改客户端。
抽象工厂模式(Abstract Factory),提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
抽象工厂模式(Abstract Factory)UML图
应用场景举例:
有华为、苹果两种手机品牌,每种品牌都有产品手机、手表、平板。
UML如下所示:
产品类
/*Pad类*/
public interface Pad {
String recreation();
}
/*Phone类*/
public interface Phone {
String recreation();
}
/*Watch类*/
public interface Watch {
String recreation();
}
华为Phone类
public class HuaWeiPhone implements Phone {
@Override
public String recreation() {
return "生产华为手机中……";
}
}
华为Pad类
public class HuaWeiPad implements Pad {
@Override
public String recreation() {
return "生产华为平板中……";
}
}
华为Watch类
public class HuaWeiWatch implements Watch {
@Override
public String recreation() {
return "生产华为手表中……";
}
}
苹果Phone类
public class ApplePhone implements Phone {
@Override
public String recreation() {
return "生产苹果手机中……";
}
}
苹果Pad类
public class ApplePad implements Pad {
@Override
public String recreation() {
return "生产苹果平板中……";
}
}
苹果Watch类
public class AppleWatch implements Watch {
@Override
public String recreation() {
return "生产苹果手表中……";
}
}
抽象工厂类
public interface AbstractFactory {
Pad getPad();
Phone getPhone();
Watch getWatch();
}
AppleFactory类
public class AppleFactory implements AbstractFactory {
@Override
public Pad getPad() { return new ApplePad();}
@Override
public Phone getPhone() {
return new ApplePhone();
}
@Override
public Watch getWatch() {
return new AppleWatch();
}
}
HuaWeiFactory类
public class HuaWeiFactory implements AbstractFactory {
@Override
public Pad getPad() {
return new HuaWeiPad();
}
@Override
public Phone getPhone() {
return new HuaWeiPhone();
}
@Override
public Watch getWatch() {
return new HuaWeiWatch();
}
}
编写测试类
public class Demo {
public static void main(String[] args) {
AbstractFactory huaWeiFactory=new HuaWeiFactory();
System.out.println(huaWeiFactory.getPad().recreation());
System.out.println(huaWeiFactory.getPhone().recreation());
System.out.println(huaWeiFactory.getWatch().recreation());
}
}
优点
- 最大的好处便是易于交换产品系列,由于具体工厂类,例 AbstractFactory huaWeiFactory=new HuaWeiFactory(),在一个应用中只需要在初始化的时候出现一次,这就使得改变一个应用的具体工厂变得非常容易,它只需要改变具体工厂即可使用不同的产品配置。我们的设计不能去防止需求的更改,那么我们的理想是让改动变得最小,现在如果你要更改不同品牌,我们只需要更改具体工厂就可以做到。
- 第二大好处是它让具体的创建实例过程与客户端分离,客户端是通过它们的抽象接口操纵实例,产品的具体类名也被具体工厂的实现分离,不会出现在客户代码中,事实上,你刚才写的例子,客户端所认识的只有产品pad、Phone、Watch。
缺点
缺点也很明显,假如要增加品牌,需要增加1个工厂类、3个产品类,太麻烦了。