I am writing a program in which I can select from a list of available Sensor
objects; upon selection and user validation, the program should instantiate that Sensor
.
The following code snippet is what I might naively do:
switch userInput
case 'Sensor A'
s = SensorA; % subclass of Sensor
case 'Sensor B'
s = SensorB; % subclass of Sensor
%...
end
There are some obvious problems here, but the biggest problem I have is making this extensible. I want to be able to create lots of various Sensor
subclasses (or have other developers generate Sensor
subclasses) without having to continuously add to this switch
statement. More generally, I want to adhere to the open/closed principle . I ought to be able to have lots of different Sensor
subclasses. (I also want to populate a popupmenu uicontrol
with the available Sensors
, but that probably gets solved if this problem gets solved generally.) Other naive solutions such as peeking into a folder full of Sensor
subclasses doesn't work very well either, since object construction may be different for each subclass.
I believe I'm looking to use the factory method pattern , but I'm not entirely sure how to implement it. I could put the above code snippet into a separate SensorFactory
, but this just moves the switch
statement around, meaning extending it requires modifying it.
How do I implement the factory method pattern correctly such that the factory object doesn't require modification every time I add a new Sensor
subclass?
Regarding extensibility you can use a containers.Map object as a hash table in your factory. Here is some simple example:
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
This class can be used like this:
At the beginning of the code create the factory:
factory = SensorFactory();
In some initialization part add new sensors on the fly:
factory.RegisterSensor('Custom Sensor', @() createCustomSensor());
factory.RegisterSensor('Specific Sensor aperture=42', @() createSpeficSensor(42));
factory.RegisterSensor('Specific Sensor aperture=666', @() createSpecificSensor(666));
NB: For automation purpose, this may be done also parsing class files in some folder. Each class having a static method to get the user name of the sensor. Just some thoughts and pseudo code here:
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
Then, in some GUI part, add a combo listing all available sensors to date:
set(myCombo, 'String', factory.GetListOfSensors());
Finally, in the run part, instantiate appropriate sensor:
index = get(myCombo, 'Value');
name = factory.GetListOfSensors();
name = name{index};
sensor = factory.CreateSensor(name);
I don't really see a reason to use the factory pattern here. A typical piece of code for matlab is:
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()
Using this, fun can be name or function handle to a function or constructor which returns your sensor object.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.