After a day of working with some rather procedural code and shoehorning it into something a bit more OO, I've concluded that this code base would've benefitted from some SOLID OOP early on.
This code base takes a set of data in a tree-like structure and generates an html tree view based on certain attributes of each data point. The tree views are not basic like a file tree, but are based on that with more features. And it needs to display differently depending on where it's being rendered. User authorization for each data point is an additional consideration.
Reasoning about this, we can see how polymorphism can benefit us here. For instance (pun intended), the basic flow of walking the tree of data would not change, except for the fact that some business logic applies to whether a node should be added or not - could be several reasons a node would not appear in the view (e.g., security, choice, etc). Filters could be used to achieve this depending on requirements. Or a class which implements filtering. Either way we slice it, the tree of data needs to be walked.
While walking the tree, whatever is rendering the tree view can either construct it on the go, or construct/serialize in one go. For the latter choice, it can hold a collection which can be added to, or receive a collection. That collection would closely model the data tree, but with whatever visibility rules applied to it by any business logic classes.
Whatever is walking the data tree should then take in business logic as a dependency. The polymorphism part is that different types of nodes can be added to the tree view depending on the result of that business logic. I'm thinking of an interface that takes in the data and returns a TreeViewNode. TreeViewNodes are FolderNodes or FileNodes (leaf nodes). But have additional properties which control other aspects of the nodes.
Hey, sounds like we can do this better than procedural with functional programming too!
(buildview (map transformToViewDataList ( filter context dataList) )
But I digress...with OO it would have different implementations of the interface for different business cases, but the same recursion. Heck you could even have different implementations of tree recursion if needed -
nodeMapperFactory = GetFactory(context);
rootNode = GetRootNode(data);
nodeMapper = nodeMapperFactory.Get(currentDataNode);
viewNode = nodeMapper.MapNode(currentDataNode);
each(WalkTree(childNode) in children);