【问题标题】:How do I correctly implement the Factory Pattern in MATLAB?如何在 MATLAB 中正确实现工厂模式?
【发布时间】:2014-07-01 18:20:21
【问题描述】:

我正在编写一个程序,我可以在其中从可用的Sensor 对象列表中进行选择;在选择和用户验证后,程序应实例化 Sensor

下面的代码sn-p是我可能天真做的:

switch userInput
    case 'Sensor A' 
        s = SensorA; % subclass of Sensor

    case 'Sensor B'
        s = SensorB; % subclass of Sensor

    %...
end

这里有一些明显的问题,但我遇到的最大问题是使其可扩展。我希望能够创建许多不同的Sensor 子类(或让其他开发人员生成Sensor 子类),而不必不断地添加到这个switch 语句中。更一般地说,我想坚持open/closed principle。我应该能够有很多不同的Sensor 子类。 (我还想用可用的Sensors 填充弹出菜单uicontrol,但如果这个问题得到普遍解决,这可能会得到解决。)其他幼稚的解决方案,例如窥视一个充满Sensor 子类的文件夹不起作用也很好,因为每个子类的对象构造可能不同。

我相信我正在寻找使用factory method pattern,但我不完全确定如何实现它。我可以将上面的代码 sn-p 放到一个单独的 SensorFactory 中,但这只是移动了 switch 语句,这意味着扩展它需要修改它。

如何正确实现工厂方法模式,以便每次添加新的Sensor 子类时都不需要修改工厂对象?

【问题讨论】:

    标签: matlab oop factory


    【解决方案1】:

    关于可扩展性,您可以在工厂中使用containers.Map 对象作为哈希表。下面是一个简单的例子:

    classdef SensorFactory < handle
    
        % Lifetime
        methods
            function [factory] = SensorFactory()
            % Creates the factory
    
                % Call super class
                factory = factory@handle();
    
                % Pre-register some well-known sensors if you want
                factory.RegisterSensor('Sensor A', @() error('TODO: Here of course use appropriate method to create sensor A'));
                factory.RegisterSensor('Sensor B', @() error('TODO: Here of course use appropriate method to create sensor B'));
                factory.RegisterSensor('Sensor C', @() error('TODO: Here of course use appropriate method to create sensor C'));
    
            end
        end
    
        methods
    
            function [] = RegisterSensor(factory, sensorName, createSensorCallback)
            % Adds new sensor to the factory    
                factory.dictionnary(sensorName) = createSensorCallback;
            end
            function [sensorList] = GetListOfSensors(factory)
            % Obtains the list of available sensors    
                sensorList = factory.dictionnary.keys;
            end
            function [sensor] = CreateSensor(factory, sensorName)  
            % Creates sensor instance
                createCallback = factory.dictionnary(sensorName);
                sensor = createCallback();            
            end
    
       end
    
        properties(GetAccess  = private)
            dictionnary = containers.Map(); % Hash table
        end   
    
    end
    

    这个类可以这样使用:

    在代码开头创建工厂:

    factory = SensorFactory();
    

    在一些初始化部分动态添加新的传感器:

    factory.RegisterSensor('Custom Sensor', @() createCustomSensor());
    factory.RegisterSensor('Specific Sensor aperture=42', @() createSpeficSensor(42));
    factory.RegisterSensor('Specific Sensor aperture=666', @() createSpecificSensor(666));
    

    注意:出于自动化目的,这也可以通过解析某个文件夹中的类文件来完成。每个类都有一个静态方法来获取传感器的用户名。这里只是一些想法和伪代码:

    classdef MySuperSensor
      methods(Static)
          funcion [name] = GetUserName()
             name = 'My super sensor';
          end
      end
    end
    
    ---
    l = dir('.\sensors');
    foreach file in l
      try
         meta = eval(sprintf('?%s', l.name)); 
         factory.Register(...GetUserName()..., ...CreateCallback...)
      catch
      end
    end  
    

    然后,在某个 GUI 部分,添加一个组合,列出迄今为止所有可用的传感器:

    set(myCombo, 'String', factory.GetListOfSensors());
    

    最后,在运行部分,实例化合适的传感器:

    index = get(myCombo, 'Value');
    
    name = factory.GetListOfSensors();
    name = name{index};
    
    sensor = factory.CreateSensor(name);
    

    【讨论】:

      【解决方案2】:

      我真的没有理由在这里使用工厂模式。一段典型的matlab代码是:

      if ischar(fun)
        if exist(fun,'function')
          fun=str2func(fun)
        else
          error('invalid input') 
        end
      end
      if ~isa(fun, 'function_handle')
        error('invalid input') 
      end
      sensor=fun()
      

      使用这个,fun 可以是返回传感器对象的函数或构造函数的名称或函数句柄。

      【讨论】:

      • 所以在我的原始示例中,“SensorA”既是要实例化的类的名称,也是用户的输入,这就是您的答案所利用的。但如果不是呢?假设类SensorA 有一个常量属性SensorName,并且那就是用户将输入的内容。在我的实际案例中,类名肯定不会与用户从弹出菜单中考虑选项列表的方式相同。
      猜你喜欢
      • 2011-07-04
      • 1970-01-01
      • 2016-02-01
      • 2012-05-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多