Question Array of singletons in ObjectFactory

knockNrod

Member
Joined
Apr 6, 2009
Messages
5
Programming Experience
10+
I'm trying to create a Data Access Layer using TCP/IP to receive regular updates from a (non-windows) computer. This data is for display (and control) of process data (steel furnace). We customize this data for each customer, and I want to separate the core data set we need for every installation from the project-specific data each customer wants displayed that's unique to their way of doing business. Oh, and some applications control multiple furnaces, which is why I have an array.

I have a base, abstract (MustInherit) class with abstract (MustOverride) methods that are called by the parsing and debugging routines. My base class assumes that all of the core data will be first in the message, and it parses that, then calls the MustOverride parsing method of the project-specific class to finish parsing the data.

Here's where I need help. I need to "get" the FurnaceData object when the message comes in, and if it doesn't exist, I need to create one (and only one). I can't figure out how to get around this without breaking the whole thing.

I can declare the constructor of my abstract base class as protected (or private) to prevent instantiation outside of my base class (object factory, if you will), but an abstract class can't instantiate its own objects because they're abstract. I can't instantiate a concrete (child) object, because I don't know what they are yet. And even if I did, that would mean my parent contained intimate information about a specific child implementation -- a recipe for disaster.

I hate to do this, but I'm thinking the only way I can accomplish this is by asking the creator of the child to implement an array of singletons. I wouldn't mind if there were some way I could think to make it contractual (abstract), but I just can't envision it.

I'm going to see if I can implement this in the child class, in the hopes that the implementation will give me some further insight, but if anyone else has some inspiring thoughts, I'd love to hear them.

-rod
 
Followup

I should mention that one of the methods of the base class is a handler for the NewMessage event, which is raised when the sockets code parses out a new message. The way this works is that the message header contains a short string identifying the message type and a byte-count. It grabs a byte-array of that size, and raises an event with the byte-array and the message type string.

I mention this, because this creates a self-reference where the message has to get a copy of the specific FurnaceData Object so it can update the data. This event handler can't know beforehand if any specific object exists for the specified furnace, so it must be a static (Shared) method.

Because of this, I can't move the management of the array of singletons to the child without at least moving this method, also. This just keeps getting worse and worse. Does anyone know why I can't combine Shared and MustInherit? I can't think of any fundamentally unsound design issues, so I'm assuming this is a compiler implementation problem.
 
Some code...

Sorry I didn't post code before, but I've coded and deleted this so many times, I didn't really have anything to post. But I'm currently at ropes end, and even though it doesn't work, it has stablized (in the trashcan, but at least it's stopped changing long enough to post something).

My current dead end came when I attempted to split the Data Access Layer (the Object Factory) from the processing of the message. This actually made sense because the FurnaceData Object receives data of both a static and dynamic nature. The parameters message comes in only once, whereas temperature readings and such come in periodically (like every fifteen to thirty seconds). This left me with two abstract and two concrete classes.

VB.NET:
Public MustInherit Class FurnaceData[INDENT]Private Shared FurnaceObjectLock As Object

Private Shared m_FurnaceData As New Generic.SortedList(Of Integer, FurnaceData)

Public Shared ReadOnly Property GetFurnaceData(ByVal FurnaceIndex As Integer) As FurnaceData[INDENT]Get[INDENT]'SyncLock ensures that two of the same are not instantiated.
SyncLock FurnaceObjectLock[INDENT]If Not m_FurnaceData.ContainsKey(FurnaceIndex) Then[INDENT]m_FurnaceData(FurnaceIndex) = [I]New ProjectFurnaceData()[/I]
[/INDENT]End If
[/INDENT]End SyncLock

Return m_FurnaceData(FurnaceIndex)
[/INDENT]End Get
[/INDENT]End Property

'A bunch more properties with associated member variables here of varying
'atomic data types.[/INDENT]
End Class

Needless to say, a New ProjectFurnaceData() can be substituted with your failed attempt of choice. As shown below, this makes intimate knowledge of the child part of the parent. A broken design, but I just can't make this work.

VB.NET:
Public Class ProjectFurnaceData[INDENT]Inherits FurnaceData

Public Sub New()
End Sub

Protected Overrides Function NewFurnaceDataObject() As FurnaceData
[INDENT]Return New ProjectFurnaceData
[/INDENT]
End Function
'A bunch of Project-Specific properties of various data types.
[/INDENT]
End Class

As I said before, the ordered list should be calling this concrete class' NewFurnaceDataObject, rather than instantiating it directly. This just creates a mad game of ring-around-the-rosies. "Can't refer to an instance method within a shared method." But you can't make it shared, because it's an abstract method. If it's not abstract, the parent can't know it exists in the child. And if you're going to make it known by the parent, why not just call new Child()?

The good news in this most recent split is that the message handling appears to be error free. Of course, I can't test it until I can get a FurnaceData object to fill with data.

Any thoughts? Anyone?
 
What I settled for....

Well, I'm down to three classes, one Abstract. I was hoping to create a situation where the maintenance programmer wouldn't need to use the concrete class except when accessing (parsing, displaying values of) the data that was project specific. This would allow me to completely wipe out the Project-Specific implementing class, and would ensure that no matter how bad they screwed this up, I would still be able to see everything in core data. But, alas, I can't make the base, abstract class enforce delivery of a child, because MustOverride and Shared, in someone's infinite wisdom, are mutually exclusive. So instead, I had to depend on the maintenance programmer, someone I don't trust to properly parse TCP streams, to properly implement an array of singletons, because the concrete product class is the only place I'm allowed to declare a shared method that returns an object I can use to control instantiation.
 
Back
Top