简单工厂模式
先来看一个问题,我们要给手机买一个手机壳,因为各种手机形状不一致,所以手机壳有很多种类,下面用代码的形式处理这个问题
String phoneName = "xxx";
// 所有的shell都是继承自PhoneShell,这里偷个懒就不写了。
PhoneShell shell = null;
if("Iphone".equals(phoneName)){
shell = new IphoneShell();
}else if("huawei".equals(phoneName)){
shell = new HuaweiShell();
}....
在这个例子的代码实现里,我们用到了很多的if else,不是说不能用if else 但是过多的if else堆砌会显得代码不是那么的简洁,这时我们把这些判断逻辑封装起来
public class PhoneShellFactory{
public static PhoneShell getPhoneShell(String phoneName){
if("Iphone".equals(phoneName)){
return new IphoneShell();
}else if("huawei".equals(phoneName)){
return new HuaweiShell();
}...
}
}
再次编写解决这个问题的代码,代码就成了下面这个样子
String phoneName = "xxx";
PhoneShell shell = PhoneShellFactory.getPhoneShell(phoneName);
代码就变得十分简洁了,但是还是有问题,虽然原本的if else没了,但是我们在编写PhoneShellFactory这个类的时候还是写了if else啊,这不是自欺欺人吗?复杂度不会消失,只会转移,所以我们把根据手机类型获得手机壳的过程封装在一个类之中,这像不像你去手机店买手机壳,只需要告诉店家你的手机类型,店家就会给你找来合适的手机壳,而不是你自己挨个去找,这就是简单工厂模式,也叫做静态工厂模式,因为只有一个获得商品的静态方法,所以没必要每次都实例化工厂对象,简单工厂模式是有违开闭原则的,开闭原则简单来说就是,允许对代码进行扩展,但是不允许对原有的代码进行修改,所以如果我们要增加商店提供的手机壳的种类就要修改PhoneShellFactory的代码,这就有违开闭原则。简单工厂模式也并不是每次都要创建新的对象,也可以在代码逻辑里加入缓存,这里就不作赘述。
工厂方法模式
前面说的简单工厂方法是有违开闭原则的,相反的,工厂方法模式是不违背开闭原则的,但是工厂方法并不是简单工厂的进阶版本,他俩的着重点是有区别的,首先我们定义一个ShellFactory接口
public interface ShellFactory {
public PhoneShell getShell();
}
接下来我们定义两个实现ShellFactory的类
public class IphoneShellFactory extends ShellFactory {
@Override
public PhoneShell getShell() {
return new IphoneShell();
}
}
public class HuaweiShellFactory extends ShellFactory {
@Override
public PhoneShell getShell() {
return new HuaweiShell();
}
}
下面我们编写购买手机壳的代码
ShellFactory sf = new IphoneShellFactory();
PhoneShell shell = sf.getShell();
类图如下
工厂模式满足了开闭原则,如果我们需要增加一个手机壳的种类,只需要编写一个实现ShellFactory的类即可,但是如果想要根据传入的手机类型创建手机壳工厂,还是需要if else逻辑判断,所以前面说工厂方法并不是简单工厂的进阶版本,他俩的着重点是有区别的,看完上面的代码可能会有一个疑问,既然都知道是要iphone的手机壳那我们直接new 一个IphoneShell不就行了,还用整这么麻烦吗?还要先new 一个IphoneShellFactory然后调用getShell才能得到IphoneShell简直不要太复杂,其实上面的代码只是简单的说明了工厂方法模式满足了开闭原则,工厂方法模式的着重点其实是隐藏创建产品的细节,且不一定每次都会真正创建产品,还是用代码来说,我们来一个实现ShellFactory的类
public class XiaomiShellFactory implements ShellFactory {
@Override
public PhoneShell getShell() {
PhoneShell shell = new XiaomiShell();
shell.rePrint(); // 手机壳重新喷涂颜色;
return shell;
}
}
这里我们在getShell方法里,加了一点细节,在实际的业务中可能创建一个产品对象有很多的细节操作,工厂方法模式的意义就是隐藏这些细节,再举一个简单的例子,比如我们买手机,同一款手机会有很多可变的参数,比如颜色,RAM,ROM,
public class Mi10Blue6$256PhoneFactory implements PhoneFactory {
@Override
public Phone getPhone() {
Phone phone = new Mi10();
phone.printColor("Blue");
phone.setRAM(6);
phone.setROM(256);
return phone
}
}
当然这个例子还是有点单薄,操作比较简单,也可以用构造函数实现,这里只是理解一下思想,不必较真,真实的业务里可能不仅仅是对POJO属性的简单操作。那不一定每次都会真正创建产品又是什么意思呢,还是用代码来说
public class XiaomiShellFactory implements ShellFactory {
static Stack stack = new Stack();
static{
// 柜台上一开始可能就摆放着一些手机壳,可能是热卖的,也可能是拿给别的顾客看,顾客没买的。
// 从仓库取手机壳相当于创建一个新的手机壳, 从柜台获取相当于没有新创建一个
stack.push(new XiaomiShell());
}
@Override
public PhoneShell getShell() {
if(stack.isEmpty()){
return new XiaomiShell();
}else{
return (PhoneShell) stack.pop();
}
}
}
这里对应到实际的业务中可能就是相应的缓存。
抽象工厂
工厂方法模式只是生产一个对象也就是一个产品,有时业务特别复杂,需要一个工厂得到多个产品怎么办?这时候就该抽象工厂出场了,从工厂方法模式来理解,一个工厂能创建一类产品,如果需要创建多类产品,那就是需要创建工厂的工厂,下面上代码,首先创建接口ElectronicsmakersFactory
public interface ElectronicsmakersFactory{
public Phone getPhone();
public Computer getComputer();
}
接着创建实现类
public XiaoMiFactory implements ElectronicsmakersFactory{
@Override
public Phone getPhone() {
return new Mi10PhoneFactory.getPhone();
}
@Override
public Computer getComputer() {
return new MiBookComputerFactory.getComputer();
}
}
public AppleFactory implements ElectronicsmakersFactory{
@Override
public Phone getPhone() {
return new Ip11PhoneFactory.getPhone();
}
@Override
public Computer getComputer() {
return new MacBookProComputerFactory.getComputer();
}
}
调用时的代码
ElectronicsmakersFactory ef = new XiaoMiFactory();
Phone phone = ef.getPhone();
Computer computer = ef.getComputer();
类图如下
总结
简单工厂模式主要注重于隐藏处理逻辑,工厂方法模式注重于隐藏装配类的细节,抽象工厂模式主要是处理复杂的业务逻辑,层级比较多。