[Newbies] Sharing a Singleton for read-only access to data

Ben Coman btc at openinworld.com
Fri May 13 01:43:35 UTC 2016


Hi Tim,

I'm not clear on which of your methods are instance-side or
class-side. Can you clarify this using the form..
XYZRecords >> filterByYear  -- for instance side
XYZRecords class >> filterByYear  -- for class side

I'm not overly familiar with Seaside or Design Pattern architectures,
but it seems you want multiple filter instances accessing one copy of
the data.  So maybe try putting your data in a class variable.
Something like this...

Object subclass: #XYZRecords
    instanceVariableNames: 'filterBlock'
    classVariableNames: 'Data'
    ...

XYZRecords class >> readFromCSVFile: aFile
    Data := OrderedCollection new.
    "for all lines from file..."
         Data add: ......

XYZRecords >> filterByYear: aYear
    filterBlock := [ :ea | ea year = aYear]

XYZRecords>>records
     ^ Data select: filterBlock

XYZRecords class >> filterByYear:  aYear
    ^self new filterByYear:  aYear


_Example usage_

XYZRecords readFromCSVFile: '~user/data.csv'.

recordset1 := XYZRecords filterByYear: 1971
recordset2 := XYZRecords filterByYear: 2000

recordset1 records inspect.
recordset2 records inspect.

No need to necessarily reset the filter.  You might just throw the
recordset instance away.

cheers -ben

On Fri, May 13, 2016 at 1:01 AM, Tim Johnson <digit at sonic.net> wrote:
> Hello Squeakers,
>
> It is cool that we have this forum for asking these kinds of questions.
>
> -- TL;DR -- I learned I probably shouldn't subclass a singleton even though it seemed so easy;  I wonder instead how to design my controller properly in an MVC paradigm;  should I learn about Factory methods and add them to my singleton?;  should I keep query methods out of my data-holding Singletons and move them to new Presenter objects as intermediaries between data-holding Singletons and views?; should I read a book?; should I give up and go home?.
>
> -- THE TASK -- I am working on a little Seaside app for my job, with a maximum of ~4 simultaneous users.  It started as skunkworks but has proved kind of useful.  My model has a couple of singletons for a couple of collections of data represented as (say) MyRecords or XYZRecords.  Singletons seemed good because the source materials being parsed into these records are ~4.0 MB apiece, so I don't want multiple copies of the data hanging around, and I only need read-only access.
>
> Maybe the singletons could be described like this:
>
> #MyReader class
>    "Singleton;  Reads some CSV or other formats;  parses into MyRecords; makes collections of MyRecords available using different query methods"
>
>
>
> For a quick-and-dirty solution to get a demo up-and-running to show my boss, I subclassed one of my Singletons (oh no!) as FilteredMyReader and added #filterByYear:, #filterBlock:, and #resetFilter methods. Inside this subclass, I just overrode the accessor for the XYZRecords to something like this:
>
> #records
> ^ records select: (self filterBlock)
>
> with some helper methods:
>
> #filterByYear: aYear
> self filterBlock: [:ea | ea year = aYear]
>
>
> ... and #resetFilter ...
>
> self filterBlock: [:ea | true ]
>
> With these new methods in my subclass, I had a drop-in replacement for my MyReader.  It worked great!  All of my query-style and-reporting-style methods were still available (because it is a subclass), but because the accessor method now was filtered, they showed only the data I wanted.  Woo-hoo!
>
> -- BUT THERE CAME TO BE A PROBLEM -- the big problem arose when multiple sessions (multiple users) were accessing the app at the same time.  Seasoned Smalltalk vets are sure to chuckle to themselves now, but I am not exactly sure why this happened (subclassing singletons is not threadsafe?).  I think when one session would change the filterBlock, it would affect another session's view into the data.  So one user may be intending to view 2016 but it may actually show 2012.  (When designing this quick-and-dirty solution, I may have mistakenly thought that each Session had a new instance of my new FilteredMyReader subclass, but probably not [!], because it was a subclass of a singleton [!]).
>
> So, I have reached the philosophical point where I get to ask "is this is a bug in my implementation, or a flaw in my design?"  A quick Google of "subclass a singleton" brings up a number of results akin to "don't do this, but if you have to, here's how: " so I think my quick-and-dirty solution might be at fault.
>
> -- SO -- as I ponder whether the flaw is in my implementation or my design, I question whether the proper approach   and a working solution would be to stop subclassing the Singleton and instead do one of the following:
>
> 1) In the Singleton, keep my query/reporting methods, but instead of returning Bags or OrderedCollections or what-have-you, have them manufacture (like a Factory?) instances of a to-be-created class of object which would be like a 'looking glass' into the data, like an intermediary between the Seaside component and the model.  Not sure what the terminology would be -- Presenter?  Controller?  I think "Art and Science of Smalltalk" (Simon Lewis) might have called it a Presenter or a PluggableSomething.
>
> 2) Similar to (1) but skip any interaction between the Singleton and the View/Session altogether.   Create a new XYZPresenter or Controller or PluggableSomething class which can have many instances around, without holding copies of the Singleton's data.  Create these on-demand from my WASession subclass (controller) or in my components (view).  These new objects will interact with the Singleton themselves in a read-only fashion.
>
> 3) Give up on Singletons for holding data and keep this stuff in a database outside of the image.  My coworkers want a traditional relational database anyway.
>
> After writing all of this up, I am still a bit confused how to proceed, because the HPI Seaside tutorial I read many years ago says a WASession subclass is supposed to be my "Controller."  So maybe I should leverage /it/ more to access the singletons / model (without storing copies of the data!).  But maybe I still would be best served by creating an additional intermediary between my WASession subclass (as controller) and the Singletons (as /part/ of the model).
>
> I hope this wasn't too much to follow, and might prove fun and instructive for someone. (Please note that while I may make references to what may be some Design Patterns, I haven't fully read the books or the Smalltalk companion, so I am speaking only with some infantile understanding of what I am talking about.)
>
> Thanks,
> Tim
>
>
> _______________________________________________
> Beginners mailing list
> Beginners at lists.squeakfoundation.org
> http://lists.squeakfoundation.org/mailman/listinfo/beginners


More information about the Beginners mailing list