In the course of studying programming and computer science, I encountered a really great resource for learning Design Patterns. It's been chilling in an open tab for a few weeks now, waiting for me to get around to digging in, and finally, thanks to catching up on some things over the holiday break, I have a chance to get in and check it out.
I'm really impressed with the clarity and detail of the explanations. The information is presented in an easy to understand way, with lots of examples and illustrations to simplify things, psuedocode for an overview, and actual code samples in a variety of programming languages for further study.
Learning Abstract Factory Methods
I started at the top and that means the first things I'm reading about are Creation patterns, and the first creation patterns I'm reading about are variations on the Factory Method. In working on clearing the hurdles of understanding, as I read I'm trying to imagine how I could use the concepts discussed in a project I'm involved with. Looking at factory methods, the clear candidate to me is WBA's database interface.
In WBA, I wanted to experiment to learn how to interface with SQL, so I have initially set it up to use a PostgreSQL interface to store data. However, this seems pretty overly complicated if someone just wants to run the program on their local machine, so it makes sense to me to include a config switch to write data to JSON as well. That way, the client can load data from whichever form of data storage the user selects. (I'd also want to write some code for syncing local JSON storage with a SQL database, so the user can switch back and forth, but that's a separate issue!)
I was thinking this already after reading the first article about factory methods, but when I read the explanation about the abstract factory method, this made even more sense. (Although admittedly I'm a little hazy on what the complete difference between a simple factory method and an abstract factory method is.)
How The Abstract Factory Method Works in WBA
I'm writing to clarify my understanding and intentions about how to set this up, particularly since I won't have time to get back into working on WBA immediately. To make use of the abstract factory pattern, I'll have to do a few things in particular:
Write the UI to use generic read and write functions
One of the main aspects of the factory method pattern is that the client doesn't know what it's specifically creating or using, and it doesn't care, as long as the interface functions are the same. For WBA, this means I would write the UI code so that any time I need to read or write a piece of data, for example, the code calls a generic read or write function on its interface object. The client passes along the information to be written, or requests the information to be read, and that's all it needs to do.
I may be able further expand use of the pattern (and genericize the code) by having various factories for the different types of entries I might use, that is, for characters, for species, for factions, etc.
Use config to select interface
Once the interface code is written generically, we need a way to pick which possible factory is going to be used to execute read and writes. This should be fairly straightforward as a configuration option (ignoring, for now, the question of "what the heck do we do when a user has data in one config, then selects the other one?"), and all the config options would automatically be loaded when the program is run.
Basically, I would create a "data interface" object, and call all read and write functions on it. That's the generic part. The config part is handled when that object is created. If we're set up to use SQL, the data interface object is created as an SQL interface, and the read and write functions get passed to the SQL interface code. If we're set up to use JSON, the data interface object is created as a JSON interface, and the read and write functions get passed to the JSON interface code. In either case the object has the same name throughout the client code, and the client code neither knows nor cares which one it is, because all the interfaces work exactly the same way (as far as the client is concerned) for both.
As an added benefit, if I later decide to support a third or fourth method of storing the user's data, implementation is as simple as creating an additional type of factory interface and updating the code that loads and interprets the config. The rest of the program still doesn't have to know anything about it.
For a bit of psuedocode, the config interpretation might include lines such as this:
if (config.data-interface == "SQL"): data-interface = SQLDataInterface() if (config.data-interface == "JSON"): data-interface = JSONDataInterface() else throw "Unknown Interface! Please reconfigure."
Using some form of the factory method will allow me to create data interfaces that operate consistently through different parts of the program, depending on an initial setting in the configuration file. This will ensure that any time the client needs to read or write user data, it does so through the selected interface, without having to run another check of the config every time, minimizing potential locations for errors and excess code in the client. The guide I linked above is discussing creating objects but I don't see any reason why the same principles and patterns wouldn't apply to calling functions, too.
Side note: there may be more use for using classes and objects in the code than I have written so far. I started the WBA project when most of my knowledge and experience involved more procedural and functional styles of programming. Since then I have had a lot more opportunities to use and see the benefits of object oriented programming. When I have time to dig into writing WBA again, I may start with revising and refactoring the SQL database interface to be more object-friendly, depending on where I can see potential benefits from doing so.
I keep rereading the explanations of the simple factory method vs the abstract factory method. If I'm understanding it correctly, what I'm proposing to use will be an instance of the abstract factory method, because I'll have a family of classes (and/or functions) for each type of data interface that I want. If I find an article or information that causes me to change my mind about this assessment, I'll be sure to come back and update this article!