简单工厂模式
先来看一个问题, 我们要给手机买一个手机壳, 因为各种手机形状不一致, 所以手机壳有很多种类, 下面用代码的形式处理这个问题
- 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();
类图如下
总结
简单工厂模式主要注重于隐藏处理逻辑, 工厂方法模式注重于隐藏装配类的细节, 抽象工厂模式主要是处理复杂的业务逻辑, 层级比较多.
来源: http://www.bubuko.com/infodetail-3492761.html