|
-
Sep 24th, 2015, 05:32 AM
#1
Thread Starter
Hyperactive Member
[RESOLVED] Help with factory design pattern
Hi Folks
This turned into a pretty long post so the TLDR version is: I'm a noob at using OOP patterns. Should I, and how can I, adapt my code (below) to use the factory pattern?
The longer version:
Im a noob at OOP concepts in practice (I usually do C firmware for 90% of my work), but have learned VB, as I went along and as I needed to. I am trying to use the language more correctly, wrt patterns and practices, etc, as I find time to fit researching them into my workflow. Prob not ideal, but its the time I have available. Consequently I am unsure if I should use a pattern to simplify the current situation I have.
Background:
At the moment I have a VB.Net 4.5 2010 forms application that talks to a physical sensor device. This device creates and stores records, where each record may be created due to certain differing conditions and each contains a number of measurement samples and some parameter information.
Currently a user would set the device started from a GUI button, which also starts a timer. As the timer elapses the handler checks if there are any new records on the device, if there are it gets the data from each record on the device. It then continues on until the user indicates, via the GUI, that the device should stop.
I have used a class Sensor to handle the all of the too-ing and fro-ing so that the GUI only handles the buttons, the timer and the ultimate display of the retrieved data.
The Sensor class currently contains a Record class. When the GUI's timer elapsed handler wants to operate it asks for a new record by calling Sensor.GetRecord(mode As Sensor.RecordingMode) which sets instantiates a Record object and reads the parametric information from the record on the device. The GUI then starts a loop that calls Sensor.GetSample() to get a number of samples from the record on the device, adding each one to the Record object (Record.AddSample(sample As Sensor.sample)). When all the samples are read the GUI adds the record to a list of records in the Sensor object, Sensor.AddRecord(record As Sensor.Record)
The parametric information read in GetRecord() is the same for all records. The number of samples a record contains however, changes depending on the Mode, it could be 512 or 256 samples.
The Sensor and Record classes
VB Code:
Class Sensor Class Sample ' Simple class that holds sample data End Class Class Record Private _mode As RecordingMode Private _samples As List(Of Sample) Private _capacity As UInteger Public Property Supply As Double ' Example parametric information Public Property Temperature As Double Public Property Mode() As Sensor.Mode Get Return _mode End Get Set(value As Sensor.Mode) _mode = value If _mode = Mode.Foo Then _capacity = 512 Else _capacity = 256 End If End Set End Property Public ReadOnly Property Samples As List(Of Sensor.Sample) Get Return _samples End Get End Property Public Sub New(mode As Sensor.Mode) Me.Mode = mode _samples = New List(Of Sample)(_capacity) End Sub Public Sub AddSample(ByVal sample As Sensor.Sample) ' Do some data manipulation here... then: Me.Samples.Add(sample) 'Add the sample record to the record End Sub End Class Public Function ReadMode() As Sensor.Mode ' Read mode from device's current record End Function Public Function ReadSupply() As Double ' Read supply from device's current record End Function Public Function ReadTemperature() As Double ' Read temperature from device's current record End Function Public Function ReadSample() As Sensor.Sample ' Read sample data from device's current record End Function Public Function GetRecord() As Record Dim mode As Sensor.Mode = ReadMode() 'Check the mode of the device Dim Record As New Record(mode) 'Create a new record with the correct sample capacity ' Do some work here to get the device to load the record from storage Record.Supply = ReadSupply() Record.Temperature = ReadTemperature() Return Record End Function End Class
The code for the GUI timer elapsed handler is something like:
VB Code:
Dim Record As Sensor.Record = Sensor.GetRecord() While Samples LeftInRecord Dim Sample As Sensor.Sample = ReadSample() Record.AddSample(Sample) ' Do some work to display the data here... End While Sensor.AddRecord(Record)
I have been trying to tidy up how this happens and make it more flexible as the Record class and GetRecord() are all within the Sensor class and file and bugs are creeping in to how the list of records is set up and handled. As I'm using a "Get" function I thought maybe this would be somewhere I could use a factory pattern, thus I duly checked MSDN for "factory pattern". This only turned up retired content: https://msdn.microsoft.com/en-us/library/ee817667.aspx which, for lack of anything else concrete, I decided to attempt to follow.
The Questions:
1: Is this a suitable place to use the factory pattern?
I'm in two minds because it seems like the Sensor class is assembling the record class for the GUI, but apart from the Mode parameter and how it affects the samples capacity, the object produced does not change; it is always a Record
2: Is there a better place to learn the recommended way to implement and use this pattern? As mentioned the MSDN article is retired (it's from 2002!) and doesn't go into a lot of detail on why certain things are done.
3: How would the actions in my current code be split up to properly use the factory pattern? I'm somewhat confused with all the different classes and abstract classes the article shows and just not sure which parts should do what in my context
Thanks!
Last edited by wolf99; Sep 24th, 2015 at 06:00 AM.
Thanks 
-
Sep 24th, 2015, 08:50 AM
#2
Re: Help with factory design pattern
Well... the thing about patterns is that they are usually geared towards certain circumstances and don't always apply to everything. they should be used when they make sense. Sometimes it's obvious right up front, sometimes its not until after the fact when you're looking at it going "hrrmmmm"... and there are times when no pattern makes sense. However, do not ever use a pattern for the sake of using a pattern. doing so would make about as much sense as me walking into a designer women's shoe store and demanding to be put into a pair of stilettos ... yeah, I could, but to what end?
In looking over your description (several times) and looking at the code, I don't see anything that lends itself to the factory pattern. Even with the getRecord method because all of the data it depends on is related to the instance of the containing class.
Based on what I know from the post, it seems that what you have is reasonable.
where I find the factory pattern works best is when I have to create an object whose properties are determined outside of the class... take databases for instance. Creating a connection, if all I'm ever going to do is talk to one database type then it's fairly easy... but let's sey I could use a SQL Server, or Oracle, or MySQL depending on configuration, or I can switch from one to another on the fly... then I will go for the factory method. I create a private Sub New (prevents the creation of the class directly) then I create a Shared Function GetConnection that returns a class of my database type - there's a project I'm working on that returns a IDataConnection... it's the Interface definition for a SQLConnection, MySQLConnection, ORAConnection, OleDbConnection ,etc... Then inside that GetConnnection method I can determine what kind of connection I need, instanciate it and return it... now my calling code doesn't care what the DBMS is ...
soooo... to answer your questions:
1 - no, I don't think so.
2 - look for examples of database factories, that's a very common factory pattern usage
3 - seeing as how I don't think it's a candidate for the factory pattern in the first place, this is a moot item.
-tg
-
Sep 24th, 2015, 11:26 AM
#3
Re: Help with factory design pattern
I don't really like nesting classes, but that's a personal preference and there's situations where I do it anyway so we'll skip that discussion.
I don't know that I can answer your 3 questions very well, so what I'll do is explain how I understand the Factory pattern, THEN make an attempt to answer them based on that understanding.
Factory is a pattern you use when you need to instantiate one or more types but you want to abstract the means by which that type is created. There are "factory methods" and "factory classes" and I've never been too big on bickering over the differences.
As a pattern, it is very helpful for putting a friendly face on constructors that are constantly changing; I use factory methods a lot in my automated tests because the constructors for my classes tend to change as I add features, and it's easier to update one factory method than it is to update 10+ unit tests that want to create a thing. If you look at it this way, you might ask the question, "Why would I ever use constructors directly, should I always write factories?" And, well, there's some reasons why you might want to always right factories, but in practice you should only use them when they're accomplishing one of your goals.
It turns out there's two situations (that I have memorized, there could be more), where a Factory is helpful:
- You have a Goose that needs to LayEggs(), but the eggs might be GoldenEgg or GooseEgg. The two types of eggs are created via completely different means, and it's not appropriate for Goose to worry about the details. An EggFactory can manage that task for the Goose.
- You have, for some reason, a circular dependency between two objects. Parent needs to have a Child, but Child needs some information from the Parent to be created. To solve this, Parent can take a ChildFactory and provide the needed information after it's been initialized.
In the first case, the more important distinction is that the Factory pattern is returning one of many possible types and contains its own logic to decide which one to use. The second case is really only a technique to handle an unavoidable circular dependency. (In general it's best to try not to create those dependencies at all.)
In either case, since control of what objects get created has been moved from the "usual" creator to the Factory implementation, you're free to do weird things like create a test harness where EggFactory always creates GoldenEgg, or that it creates a TestGoldenEgg that has a random amount of gold instead of consulting a financial database to determine the right amount. This makes Factory fall under the umbrella of "Inversion of Control", a very powerful concept in object-oriented design.
So, looking over your situation:
- I don't think I'd reach for Factory here. You have one kind of Record, and it's usually created the same way, and it's coupled enough with Sensor that it might not make sense to break the coupling via abstraction.
We have to ask, "Will Record change its constructor?" before we create a RecordFactory. It doesn't seem likely in this design. It might change how it responds to its mode parameter, but that might not impact how Sensor behaves. I would wait to create a RecordFactory until I want to generate several derived Record types, or I start rapidly iterating its constructor design.
The tricky thing about Factory is you could use it here, and it wouldn't hurt much. But it tends to imply there's something complex about creation, and that doesn't seem to be the case. - MSDN is not a good place to learn about design patterns. It is focused much more on documenting Windows and the libraries used to develop for Windows.
The internet is an OK place to learn about design patterns. There are some very good articles. There are some sites that pull them together in a coherent way. There are also some very bad articles with misinformation, and sites that haphazardly mix both kinds of articles. Never read just one article, and try to find reputable sources.
The best places to learn about design patterns are well-reviewed, dedicated books. I like "Head-First Design Patterns", it's oriented for readability and meant to be more fun than most texts. The "best" book is simply named "design patterns" but is very academic and not fun to read. Most of what I've learned has come from reading HFDP, some books about automated testing, then seeking articles by people like Michael Feathers, Martin Fowler, and Bob Martin. Lots of books focusing on "Agile" development are accidentally great resources for patterns. - I don't know if there's value in that exploration.
The thing that only marginally concerns me is that a record has varying capacities based on the Mode with which it was created. That suggests you could make two derived Record classes, each with a fixed capacity. But this also assumes that the things reading the samples do different things based on that capacity, because if that's true then each derived Record would somehow abstract that work. I'd have to know a lot of domain-specific stuff to figure out if that's even the case. I can certainly bend this code so that Factory makes sense, but I don't know if forcing it in that direction produces any benefit. In general, it's best to not use a design pattern until its absence is creating a problem that its presence could solve.
Often, the best way to find out if something's a good idea is to just try it. If it feels clunky, it's probably not a good idea! If you're using source control and writing automated tests, you're always free to try something crazy with the assurance you can't permanently break something. If you're not using source control or tests, well, get there so you can make mistakes safely!
This answer is wrong. You should be using TableAdapter and Dictionaries instead.
-
Sep 25th, 2015, 05:09 AM
#4
Thread Starter
Hyperactive Member
Re: Help with factory design pattern
Many thanks for your thorough replies, much appreciated!
I now understand that this situation is likely not a good candidate for the pattern. The reasoning that started me on this path was that I also am not a fan of nesting classes, it feels... burdensome. Yet the Record class needs to use things that are defined in the Sensor class, such as the Mode enumeration, which are intrinsically something that is part of the sensor.
This circular logic is *kind of* what I started out trying to solve I guess. thinking about this more, I have managed to move most, but not all of the Sensor specific items out of the Record class so that is less complex at least.
MSDN is usually my starting point because, although I am painfully aware of how hard it is to learn from it rather than use it as a reference (what's the point in having somewhere to look stuff up if you can only find the right information if you already know the thing you want to look up though? ). I have tried to read the GOF book, but it was pretty hard going on the kindle and I have to admit I gave up. I will try that Head first book you recommended Sitten Spynne, as it's the second time I have come across mention of it.
In relation to the varying capacities and how this affects the reading of the samples: The samples them selves are still retrieved from the device in the same way. However, when the mode is non-default, then there is a lot of extra leg work before and after the reading of the samples to correctly load the records into memory on the device and make sure the list of records is at the correct state in relation to that. Currently this all is implemented as part of the Sensor class and the Sample and Record classes are more really just data storage, as the functions (eg GetTemperature()) that do this retrieval can also be used outside of this purpose, eg if the user asks the GUI to specifically just read the sensor temperature.
Thanks again for your thoughts, T
Thanks 
-
Sep 25th, 2015, 08:09 AM
#5
Re: [RESOLVED] Help with factory design pattern
The reasoning that started me on this path was that I also am not a fan of nesting classes, it feels... burdensome. Yet the Record class needs to use things that are defined in the Sensor class, such as the Mode enumeration, which are intrinsically something that is part of the sensor.
That doesn't mean it has to be a nested class (not a fan of them either except in rare cases, and usually then they are friend or private, not public.)
you can have two classes and one produces the other. The Enum can still also be defined in the Sensor class, as long as the class and the enum are public, or friend even, you still have access to it.
-tg
-
Sep 25th, 2015, 08:11 AM
#6
Thread Starter
Hyperactive Member
Re: [RESOLVED] Help with factory design pattern
D'oh, of course! The enum is already public too
Thanks 
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|