4 ms·
For me, the epiphany about design patterns happened some fifteen years ago, when I was trying to understand and learn the abstract factory pattern, in PHP back
by BerislavLopac 8y ago
For me, the epiphany about design patterns happened some fifteen years ago, when I was trying to understand and learn the abstract factory pattern, in PHP back then. After constructing all the concrete factory classes and the whole setup, I suddenly realised that, in PHP, it all boils down to a simple:
$className = 'FooBar';
$newInstance = new $className();
And other dynamic languages, like Javascript and Python, have their own mechanisms to dynamically define the class you want to instantiate. This is not about dynamic vs static languages -- it's simply that I then realised that the GoF patterns are not some generic programming constructs; instead they are simply recipes for dealing with certain specific type of constraints arising from a specific set of programming tools. Dynamic languages (or any other tool) have their own constraints, and there are "design patterns" around them.
- mojuba 8y agoAgreed, generally class factories make little sense in languages where a class reference lives at run-time in some or other form. Even some static languages have this, e.g. ObjC. I would even go with a broader generalization and say that existence of patterns (i.e. things that require a lot of typing) in a given language means the language is underdesigned and/or is behind the times. Which is certainly true for Java for example.
- watwut 8y agoWhen you know in advance which object to use and object does not require configuration, instantiate that object without factory or dynamic construct. The factory is useful only if you are a.) about to wire object into something complex or b.) create it based on complicated external rules or c.) decided that some group of objects is better to be initialized all at the same place for code readability (rare). Even in java, there is not other use. As in, your php code foes not replaces factory and using factory where you phone code works is unnecessary overkill.
- realharo 8y agoYou could still do the following in Java: Class<? extends FooInterface> c = FooBar.class; FooInterface newInstance = c.newInstance() But people usually choose not to, because it still leaves the construction details up to the caller (and forces the class to have a no-arg constructor). The point of a factory is to create a fully "configured" object, e.g. maybe the factory has a set of specific constructor arguments it uses for all the objects it creates, that the caller then doesn't have to know about, etc. It's true however that people would simply use higher order functions for this in JavaScript, e.g. function createButtonFactory(color, background) { return function(text) { return { type: 'button', color, background, text } } } const buttonMaker = createButtonFactory('grey', 'blue') and then you can pass `buttonMaker` to somewhere that wants to create buttons by just specifying the text (i.e. some function that will be calling `buttonMaker('hello')`) This has nothing to do with the language being "dynamic" though, it's about having this specific feature. You could do the same thing in C++ now that it has lambdas. The contract of the thing that uses the factory is "I need to be able to create buttons by just specifying their text", i.e. type ButtonMaker = (text: string) => Button function loadGui(buttonMaker: ButtonMaker) so the factory has to take care of all the other details (if any) to make that possible.
- annabellish 8y agoNnnh, only in the really straightforward case. It's often not the case that you can just `new` what you want with no parameters, and _that_'s what the factory pattern covers. To take the archetypical example, let's consider our database. We just want something that implements the `Database` interface, but we can't just `new MySqlDb()` because it needs a whole bunch of data to connect - so we end up needing something more complicated which can build and configure something implementing the interface we want without requiring us to know anything about the implementation. What people mean when they say better languages have this behaviour as just something obvious within the language semantics is like, when you simplify it down you don't get `new $className()`, you get a function of `() => Database`. Any language with higher order functions that can properly represent function types can, instead of building all this cruft to construct factories, just accept that the concept of "something you don't need to give any data to but which returns you a configured X` _is_ a function from nothing to X- and so all the behaviour is "built in". The code which deals with databases just needs `() => Database` as a parameter, and then your composition root simply provides the right function. Exactly the same expressive power as an abstract factory, but it's so straightforward it doesn't need a fancy name.
- ape4 8y agoThat's pretty cool. But I would prefer code that checks the existence of the class at compile time.
- thom 8y agoThe implementation might be trivial, the design choice is not.
- projektfu 8y agoYes, that may work for that case, but an abstract factory can do things like choose the appropriate underlying class that you don't know of, returning the interface that you do know. In a duck-typed language like Javascript or PHP, it's maybe not obvious unless you test on type for some reason. Some languages, like Smalltalk, consider every instance of Class to be an abstract factory. If you change #new you can have it return anything, although you should leave #basicNew alone. Some languages, like Objective C, have a bizarre idiom where you ask specifically for one thing (NSArray?) and get another that implements NSArray's protocol. OK... Where the usefulness of design patterns really comes into play is in naming the thing. My undergrad brain spent way too long trying to understand what COM's IClassFactory was doing when it would have been nicely named IAbstractFactory or IFactory or simply IClass. By abusing the conventional term, it made it unnecessarily hard for me. It didn't help that COM called the objects that implement IClassFactory "Classes" or "CoClasses". While the designers of COM did a fine job overall, you kind of wonder if they were new to OOP when they were first writing it, and couldn't agree on terms.