Skip to content

Latest commit

 

History

History
331 lines (242 loc) · 11.7 KB

20.谈谈对「简单工厂模式」和「工厂方法模式」的理解.md

File metadata and controls

331 lines (242 loc) · 11.7 KB

谈谈对「简单工厂模式」和「工厂方法模式」的理解

参考答案

定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。

  1. 何时使用
    1. 用户需要一个类的子类的实例,但不希望与该类的子类形成耦合
    2. 用户需要一个类的子类的实例,但用户不知道该类有哪些子类可用
  2. 优点
    1. 使用工厂方法可以让用户的代码和某个特定类的子类的代码解耦
    2. 工厂方法使用户不必知道它所使用的对象是怎样被创建的,只需知道该对象有哪些方法即可。
  • 简单工厂模式

    简单工厂模式又称静态工厂方法模式。它存在的目的很简单:定义一个用于创建对象的接口。

    如果一个一些对象(产品),已经确定了并不易改变和添加新的产品,那么就可以使用简单工厂模式

    interface Phone {
        void call();
    }
    
    class HwMobilePhone implement Phone {
        @Override
        public void call() {
            System.out.println("Hw make a call");
        }
    }
    
    class OnePlusMobilePhone implement Phone {
        @Override
        public void call() {
            System.out.println("OnePlus make a call");
        }
    }
    
    class Factory {
        Phone produce(String product) {
            if(product.equals("Hw"))
                return new HwMobilePhone();
            else if(product.equals("OnePlus"))
                return new OnePlusMobilePhone();
            else throw new IllegalArgumentException("No such product");
        }
    }
    
    public class SimpleFactoryPattern {
        public static void main(String args[]) throws Exception{
            Factory factory = new Factory();
            factory.produce("Hw").call();
            factory.produce("OnePlus").call();
        }
    }

    可以看出,简单工厂模式是不易维护的,如果需要添加新的产品,例如要增加一个 MiMobilePhone,则整个系统都需要修改。

  • 工厂方法模式

    工厂方法模式去掉了简单工厂模式中工厂方法的静态属性,使得它可以被子类继承。这样在简单工厂模式里集中在工厂方法上的压力可以由工厂方法模式里不同的工厂子类来分担。

    interface Phone {
        void call();
    }
    
    class HwMobilePhone implement Phone {
        @Override
        public void call() {
            System.out.println("Hw make a call");
        }
    }
    
    class OnePlusMobilePhone implement Phone {
        @Override
        public void call() {
            System.out.println("OnePlus make a call");
        }
    }
    
    interface IFactory {
        Phone produce();
    }
    
    class HwFactory implement IFactory {
        @Override
        public Phone produce() {
            return new HwMobilePhone();
        }
    }
    
    class OnePlusFactory implement IFactory {
         @Override
        public Phone produce() {
            return new OnePlusMobilePhone();
        }
    }
    
    public class FactoryPattern {
        public static void main(String args[]) {
            IFactory factory;
            factory = new HwFactory();
            factory.produce().call();
            factory = new OnePlusFactory();
            factory.produce().call();
        }
    }

工厂方法模式和简单工厂模式在定义上的不同是很明显的。工厂方法模式的核心是一个抽象工厂类,而不像简单工厂模式, 把核心放在一个实类上。工厂方法模式可以允许很多实的工厂类从抽象工厂类继承下来, 从而可以在实际上成为多个简单工厂模式的综合,从而推广了简单工厂模式。 反过来讲,简单工厂模式是由工厂方法模式退化而来。设想如果我们非常确定一个系统只需要一个实的工厂类, 那么就不妨把抽象工厂类合并到实的工厂类中去。而这样一来,我们就退化到简单工厂模式了

蛋友答案
From Taonce
简单工厂 工厂
是否有基础的工厂类
是否有实现基础工厂类的具体类
是否有基础的产品类
产品类是否可拓展 可以 可以
工厂类可扩展 不可以(需要改变基础工厂类,如果增加产品类,那么工厂类就要增加这种产品类的判断) 可以(可以直接添加产品类,通过反射机制获取的具体产品,不需要修改代码,只需要增加产品类就行)
From safier

简单工厂模式

简单工厂模式是属于创建型模式,又叫做静态工厂方法(Static Factory Method)模式。简单工厂模式是一个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式,可以理解为是不同工厂模式的一个特殊实现。

image

具体实现如下:

  1. 定义一个操作接口:
public interface Operation {
 
    public double getResult(double numberA,double numberB) throws Exception;
 
}
  1. 定义具体的操作类
public class Add implements Operation{
 
    // 加法计算
    public double getResult(double numberA, double numberB) {
 
        return numberA + numberB;
    }
}
 
 
public class Sub implements Operation{
 
    // 减法计算
    public double getResult(double numberA, double numberB) {
        return numberA-numberB;
    }
}
 
 
public class Mul implements Operation{
 
    // 乘法计算
    public double getResult(double numberA, double numberB) {
        return numberA * numberB;
    }
}
 
 
public class Div implements Operation {
 
    // 除法计算
    public double getResult(double numberA, double numberB) throws Exception {
        if (numberB == 0) {
            throw new Exception("除数不能为0!");
        }
        return numberA / numberB;
    }
}
  1. 定义简单工厂类
public class EasyFactory {
 
    // 简单工厂,根据字符串创建相应的对象
    public static Operation createOperation(String name) {
        Operation operationObj = null;
        switch (name) {
            case "+":
                operationObj = new Add();
                break;
            case "-":
                operationObj = new Sub();
                break;
            case "*":
                operationObj = new Mul();
                break;
            case "/":
                operationObj = new Div();
                break;
        }
        return operationObj;
    }
}
  1. 客户端代码
public class Client {
 
    public static void main(String[] args) throws Exception {
 
        Operation add = EasyFactory.createOperation("+");
        Operation sub = EasyFactory.createOperation("-");
        Operation mul = EasyFactory.createOperation("*");
        Operation div = EasyFactory.createOperation("/");
 
        System.out.println(add.getResult(1, 1));
        System.out.println(sub.getResult(1, 1));
        System.out.println(mul.getResult(1, 1));
        System.out.println(div.getResult(1, 1));
    }
}
  1. Result:
2.0
0.0
1.0
1.0

缺点:简单工厂模式能够根据外界给定的信息,决定究竟应该创建哪个具体类的对象。明确区分了各自的职责和权力,有利于整个软件体系结构的优化。

优点:很明显工厂类集中了所有实例的创建逻辑,容易违反GRASPR的高内聚的责任分配原则

工厂方法模式

工厂方法模式Factory Method,又称多态性工厂模式。在工厂方法模式中,核心的工厂类不再负责所有的产品的创建,而是将具体创建的工作交给子类去做。该核心类成为一个抽象工厂角色,仅负责给出具体工厂子类必须实现的接口,而不接触哪一个产品类应当被实例化这种细节。

image

  1. 首先定义一个工厂接口:
import org.zero01.operation.Operation;
 
public interface Factory {
 
    public Operation createOperation() ;
 
}
  1. 然后是具体的工厂类
// 加法类工厂
public class AddFactory implements Factory{
 
    public Operation createOperation() {
        System.out.println("加法运算");
        return new Add();
    }
}
 
// 减法类工厂
public class SubFactory implements Factory{
 
    public Operation createOperation() {
        System.out.println("减法运算");
        return new Sub();
    }
}
........
  1. 运算类跟简单工厂一样
  2. 客户端代码:
public class Client {
 
    public static void main(String[] args) throws Exception {
 
        // 使用反射机制实例化工厂对象,因为字符串是可以通过变量改变的
        Factory addFactory = (Factory) Class.forName("org.zero01.factory.AddFactory").newInstance();
        Factory subFactory=(Factory) Class.forName("org.zero01.factory.SubFactory").newInstance();
 
        // 通过工厂对象创建相应的实例对象
        Operation add = addFactory.createOperation();
        Operation sub = subFactory.createOperation();
 
        System.out.println(add.getResult(1, 1));
        System.out.println(sub.getResult(1, 1));
    }
}

优点:

  • 子类提供挂钩。基类为工厂方法提供缺省实现,子类可以重写新的实现,也可以继承父类的实现。加一层间接性,增加了灵活性。
  • 屏蔽产品类。产品类的实现如何变化,调用者都不需要关心,只需要关心产品的接口,只要接口保持不变,系统中的上层模块就不会变化。
  • 典型的解耦框架。高层模块只需要知道产品的抽象类,其他的实现类都不需要关心,符合迪米特法则,符合依赖倒置原则,符合里氏替换原则。
  • 多态性:客户端代码可以做到与特定应用无关,适用于任何实体类。

缺点:需要Creator和相应的子类作为factory method的载体,如果应用模型确实需要creator和子类存在,则很好;否则的话,需要增加一个类层次。

两种模式的比较

工厂模式中,要增加产品类时也要相应地增加工厂类,客户端的代码也增加了不少。工厂方法把简单工厂的内部逻辑判断转移到了客户端代码来进行。

你想要加功能,本来是改工厂类的,而现在是修改客户端。而且各个不同功能的实例对象的创建代码,也没有耦合在同一个工厂类里,这也是工厂方法模式对简单工厂模式解耦的一个体现。工厂方法模式克服了简单工厂会违背开-闭原则的缺点,又保持了封装对象创建过程的优点。

但工厂方法模式的缺点是每增加一个产品类,就需要增加一个对应的工厂类,增加了额外的开发量。