Simple factory and Factory Method Design pattern difference - java

I am learning design patterns newly & I am trying to understand the difference between Simple Factory & Factory Method Pattern. First I want to clear that , I tried reading lot of articles from Stack-overflow and other sites regarding the same but that doesn't helped me.
Here is my question:
Lets consider I have a product hierarchy as shown below:
I have written a simple Factory class as shown below
public class SimpleItemFactory {
static Item getItem(String type) {
if(type.equals("Cake")) {
return new Cake();
}else if(type.equals("Chocolate")) {
return new Chocolate();
}else {
return null;
}
}
}
so now I have all the object creation in one place , so if tomorrow any changes occurs[Like constructor needs one parameter] we need to change in only one place. But it breaks OPEN CLOSED principle as if tomorrow we add more item we need to change getItem() methods if condition. So we go for Factory Method Pattern
We create Factory class as shown below:
public abstract class ItemFactory {
abstract Item getItem();
}
class CakeFactory extends ItemFactory {
#Override
Item getItem() {
return new Cake();
}
}
class ChocolateFactory extends ItemFactory {
#Override
Item getItem() {
return new Chocolate();
}
}
class Client{
public static void main(String[] args) {
Item chocolate = new ChocolateFactory().getItem();
System.out.println(chocolate);
}
}
Now when the client want to add new Item called IceCream, they just create new Factory called IceCreamFactory and create IceCream from that as shown below:
class IceCreamFactory extends ItemFactory{
#Override
Item getItem() {
return new IceCream();
}
}
class Client{
public static void main(String[] args) {
Item iceCream = new IceCreamFactory().getItem();
System.out.println(iceCream);
}
}
Is my understanding correct?
We satisfied Open closed principle here, but for each product(Item) we need one Factory class, does not it become manageable nightmare?
NOTE: Article I was referring https://www.codeproject.com/Articles/1135918/Factory-Patterns-Factory-Method-Pattern?msg=5380215#xx5380215xx

Your understanding actually is correct, just you need to note that every design pattern is made to solve at least one single issue, sometimes it could bring with it some other complexities or side effects, which means there is no perfect design pattern that could solve every problems.
For learning purposes you apply design patterns one by one (that makes the real power of design patterns sames to be shy or hiding), however in a real world context design patterns are mixed together (or even you can invent a new one :p) for the purpose of creating something that satisfy most your needs and becomes near to ideal, you can meet for example the Builder pattern mixed with Factory pattern or Factory pattern with Strategy pattern, or even the three of them mixed together...
For your case here I propose for example to use Factory Method Pattern together with Simple Factory Pattern combined with Dependency Injection Pattern to create something totally beautiful and at the same time satisfying the Open closed principal.
class ItemFactoryContainer() {
private Map<String, ItemFactory> factories = new HashMap<>();
public void register(String name, ItemFactory factory) {
factories.put(name, factory);
}
public ItemFactory getFactory(String name) {
return factories.get(name);
}
}
public class ItemFactoryTest {
public static void main(String...args) {
ItemFactoryContainer factoryContainer = new ItemFactoryContainer();
factoryContainer.register("choclate", new ChocolateFactory ());
factoryContainer.register("cake", new CakeFactory ());
factoryContainer.register("iceCream", new IceCreamFactory ());
Chocolate choclate = factoryContainer.getFactory("choclate").getItem();
Cake cake = factoryContainer.getFactory("cake").getItem();
}
}

Answers (by #Mouad EL Fakir and #François LEPORCQ) are about the static factory. That is your first part of the code.
There are two more flavors namely Factory Method and Abstract Factory)
Second part of your code is using CakeFactory and ChocolateFactory, you are trying to use Factory Method (though your naming suggests Abstract Factory). The usage of factory method getXXX() here is incorrect. The purpose of these patterns is different. In your code you are not achieving anything but increasing number of classes. (though increased number of classes and parallel hierarchies is documented as cost associated with Factories)
I have answered a similar questions recently see if those answers are helpful
Role of Creator in Factory Pattern
What are the real benefits of using the Abstract Factory in the following example, instead of the factory method?

I think in your example a factory seem useless because your Cake and Chocolate constructors don't need any args.
A factory is useful when you want to construct a complex object with many args to respect the DIP (Dependency Inversion Principle) and avoid embarrassing couplings.
In addition, your example seems to violate the LSP (Liskov Substitution Principle). Cake and Chocolate classes have nothing in common, and as evidence, your abstract super class is named Item which is a very generic name.
For me, with complex uncommon objects, the choice of one factory by class is better, and effectively respect the OCP (Open Closed Principle).
Your first example can be useful to instantiate classes which inherits the same superclass, but using your classes as arg and reflection (using java.lang.reflect) to call the constructor not just using String evaluation. (Your IDE is not able to autocomplete that) and in case of no match don't return null, Throw an IllegalArgumentException, it's more correct.
Like this :
import java.lang.reflect.Constructor;
public class SimpleItemFactory {
public <T extends Item> T createItem(Class<? extends Item> itemClass) {
try {
// construct your dependencies here
// and inject them in the getConstructor
Constructor<? extends Item> constructor = itemClass.getConstructor();
return (T)constructor.newInstance();
} catch (Exception e) {
throw new IllegalArgumentException();
}
}
}
and use it like this :
class Client {
public static void main(String[] args) {
SimpleItemFactory factory = new SimpleItemFactory();
IceCream iceCream = factory.createItem(IceCream.class);
System.out.println(iceCream);
Cake cake = factory.createItem(Cake.class);
System.out.println(cake);
Chocolate chocolate = factory.createItem(Chocolate.class);
System.out.println(chocolate);
}
}
If you have no dependencies you can implement the createItem() method as static directly in your abstract Item class.
See this book, it's a great resource : Head First Design Patterns
OCP is just Open for extension Close for modification Principle. If you need to open for modification your factory to add a new class (a new case to manage in a switch or a if), no, your factory is not "OCP".
You sould'nt calculate a tax in a constructor, a constructor should just... construct an object.. You could use a pattern like strategy to have many taxesCalculator and inject them into a constructor, with an IOC (Inversion of Control) mechanism like dependencies injection or in a simple way with.....a factory (it's acceptable), but not with a simple static method in your class.
I'm sorry for my bad english, it's difficult for me to answer to a complex question like this.

Related

Explanation of Java Factory Design Pattern or Factory Class

I am going through HackerRank and had a quick question regarding the Factory Design Pattern or Factory Class. I am going through a basic challenge (https://www.hackerrank.com/challenges/java-factory/problem) and was able to solve it (code shown below). I wrote the portion of the code that is indicated by the comments below, while the rest was provided.
import java.util.*;
import java.security.*;
interface Food {
public String getType();
}
class Pizza implements Food {
public String getType() {
return "Someone ordered a Fast Food!";
}
}
//I implemented the part starting here
class Cake implements Food {
public String getType() {
return "Someone ordered a Dessert!";
}
}
class FoodFactory {
public Food getFood(String order) {
if (order.equalsIgnoreCase("Pizza")){
return new Pizza();}
else return new Cake();
}//End of getFood method; this is the end of the part I implemented
}//End of factory class
public class Solution {
public static void main(String args[]){
Do_Not_Terminate.forbidExit();
try{
Scanner sc=new Scanner(System.in);
//creating the factory
FoodFactory foodFactory = new FoodFactory();
//factory instantiates an object
Food food = foodFactory.getFood(sc.nextLine());
System.out.println("The factory returned "+food.getClass());
System.out.println(food.getType());
}
catch (Do_Not_Terminate.ExitTrappedException e) {
System.out.println("Unsuccessful Termination!!");
}
}
}
I have spent quite a bit of time reading through several examples online of the Factory Design Pattern, but it isn't exactly clear to me what is the purpose of the Factory Pattern and why it is beneficial or what it is simplifying/what problem it is solving. Similarly, trying this actual example hasn't quite elucidated the issue to me.
Can someone explain this in a very basic way and similarly, what would be alternatives to using the Factory Pattern? Perhaps this code that was provided in this exercise oversimplified the issue and this is why I am not clear on what the Factory accomplished. Thank you for some help as some real world color would help greatly. I have read about various design patterns and know what they are but I don't understand the issue well enough having limited real world experience with them
The basic idea of a factory is 2 things:
Obfuscate to the user (the developer) how objects are created
Put all object creation through a single place of origin.
Why do you need the factory in the first place?
Well the easiest answer is so that you could control the object creation.
Let's take a real world example:
You want to write an analytics for your app.
You happily write a class that implements some library for analytics that you use.
And go over all of your app and write AnalyticsEventManager().sendEvent(blabla)
What is the problem with this?
There came a day you want to add another analytic or replace the
current one
How do you check that all the places you need the analytic it is actually invoked?
Well factory to the rescue.
instead of AnalyticsEventManager().sendEvent(blabla)
You write an interface that has a "sendEvent" method
interface AnalyticEventSender {
void sendEvent(String eventData);
}
Then you have a few instances of different classes that implement this analytic
class FacebookAnalytic implements AnalyticEventSender {
#Override
public void sendEvent(String eventData){
System.out.println("I am facebook analytics sender:" + eventData);
}
}
Then you have
class TestAnalytic implements AnalyticEventSender {
#Override
public void sendEvent(String eventData){
System.out.println("I am test analytics sender:"+eventData);
}
}
Then you have analytic factory
class AnalyticFactory {
public static AnalyticEventSender create(){
if(allowFacebookAnalytic){
return new FacebookAnalytic();
}else {
return new TestAnalytic();
}
}
}
and so just like that you were able to replace ALL the instances of your analytic based on some boolean (the reason for changing the analytic is up to the discretion of the one who wrote the code)
And now instead of doing AnalyticEventManager().sendEvent you would write AnalyticFactory.create().sendEvent(blabla)
So now, If you want to check that your events are actually printed the way you want them to be printed, you just replace the instance that is returned in the factory with the TestAnalytic and check that the events are printed, without actually going through the real facebook module.
This is true for many other applications, not just analytics.
I suggest you read Effective Java, 3rd Edition, by Joshua Bloch, Item 1. You can look it up in Google, but one of the links is Effective Java, 3rd Edition.

Interface to enforce generic static method in Java

I have a Java class Model which models some data from my remote database. I want all data models in my project to be able to supply a builder from a Map<String, Object> instance (in practice, I'm working with SnapshotParser<Model> parsers with Firestore, but I'll just call getData() in every model). This should look something like:
public class Model {
private String name;
public Model(String name) { this.name = name; }
public static SnapshotParser<Model> getDocParser() {
return docSnapshot -> {
Map<String, Object> data = docSnapshot.getData();
return new Model(data.getOrDefault("name", "John Doe"));
};
}
}
Note that I'll have several models (Model2, Model3...) which will also be required to provide such an interface. To enforce this behavior, I created a DocParserSupplier generic class for my model classes to implement:
public interface DocParserSupplier<T> {
static SnapshotParser<T> getDocParser();
}
This doesn't work for two reasons (as Android Studio informs me):
static methods of interfaces must have a default implementation. I can't do that without knowing T.
I get the "T cannot be referenced in static context" error.
If remove the static keyword from the above interface, I can do what I want but it would require I create an actual instance of the Model to get the parser. It would work but it makes more sense if the method is static.
Is there a Java way to do what I want?
EDIT: My specific use case is in matching RecyclerViews to documents in my database. Constructing the FirestoreRecyclerOptions object requires a parser to convert key-value data to a Model:
FirestoreRecyclerOptions<Model1> fro1 = new FirestoreRecyclerOptions.Builder<Model1>()
.setQuery(query1, Model1.getDocParser())
.build();
FirestoreRecyclerOptions<Model2> fro2 = new FirestoreRecyclerOptions.Builder<Model2>()
.setQuery(query2, Model2.getDocParser())
.build();
Interfaces enforce behavior of instances, so that references to any object which has that behavior can be passed around in a type-safe way. Static methods on the other hand, don't belong to any particular instance of an object; the class name is essentially just a namespace. If you want to enforce behavior, you will have to create an instance somewhere (or use reflection, if it is absolutely necessary to ensure a class has a particular static method).
Unless this system is going to be opened up for extension, where others can define their own models, I would say ditch the DocParserSupplier interface altogether and call the static methods exactly as you are now, or factor them out into a factory interface + implementation. The factory option is nice because you can replace the production implementation with a fake implementation that returns dummy parsers for tests.
Edit: Doc Parser Factory
public interface DocParserFactory {
SnapshotParser<Model1> getModel1Parser();
SnapshotParser<Model2> getModel2Parser();
...
SnapshotParser<Model1> getModelNParser();
}
...
// The implementation of each getModelXParser method
class DocParserFactoryImpl {
SnapshotParser<Model1> getModel1Parser() {
return docSnapshot -> {
Map<String, Object> data = docSnapshot.getData();
return new Model(data.getOrDefault("name", "John Doe"))};
}
...
}
...
private DocParserFactory docParserFactory;
// You can inject either the real instance (DocParserFactoryImpl) or a
// test instance which returns dummy parsers with predicable results
// when you construct this object.
public ThisObject(DocParserFactory docParserFactory) {
this.docParserFactory = docParserFactory;
}
...
// Your code
public void someMethod() {
...
FirestoreRecyclerOptions<Model1> fro1 = new
FirestoreRecyclerOptions.Builder<Model1>()
.setQuery(query1, docParserFactory.getModel1Parser())
.build();
FirestoreRecyclerOptions<Model2> fro2 = new
FirestoreRecyclerOptions.Builder<Model2>()
.setQuery(query2, docParserFactory.getModel2Parser())
.build();
...
}
It's not so much to do with static or non-static, as it is with the fact that you cannot create an instance of a generic object without passing the type parameter(s) one way or another. In fact, I answered a similar question a few days ago, when somebody wanted to use enums to get the required builder.
In short, you cannot write a method <T extends AbstractBuilder> T builder(final SomeNonGenericObject object) (or, in this case, <T extends AbstractBuilder> T builder()) without passing T in some form. Even though it will make sense at runtime, the compiler can't figure out what generic type to use if you don't tell it which one it is.
In Java 8, you can solve this elegantly with method references. I don't know much about Android, but I believe you're still on Java 6 there, so this wouldn't work.
Anyway, you can have something like the following:
public <T extends AbstractBuilder> T builder(final Supplier<T> object) {
return supplier.get();
}
final Supplier<AbstractBuilder> model1BuilderSupplier = Model1Builder::new;
builder(model1BuilerSupplier)
.setQuery(query1, Model1.getDocParser())
.build();
It's not exactly what you want, but the way you're trying to go about it will not work.

Factory Method pattern vs composition

From GoF chapter about the Factory Method pattern:
Define an interface for creating an object, but let subclasses decide which class to
instantiate. Factory Method lets a class defer instantiation to subclasses.
The idea is to let subclasses decided which class to instantiate, and GoF's implementation of the idea, is to provide an abstract method in the superclass, that subclasses need to override, and thus providing their own instantiation logic.
What I don't understand is, why implementing it using an abstract method, and not using a class member which is the factory. I'll explain.
This is the GoF way:
public abstract class Creator {
public void doStuff() {
Product product = createProduct();
/* etc. */
}
public abstract Product createProduct();
}
Usage:
MyCreator myCreator = new Creator() {
#Override
public Product createProduct() {
return new MyProduct();
}
}
myCreator.doStuff();
But why bother with the subclassing, etc.? I suggest this approach:
public class Creator {
private Factory factory;
/* constructor */
public Creator(Factory factory) {
this.factory = factory;
}
public void doStuff() {
Product product = factory.createProduct();
/* etc. */
}
}
And this is how you use it:
MyFactory myFactory = new MyFactory();
Creator creator = new Creator(myFactory);
creator.doStuff();
So what is the benefit in GoF's approach? Why not composing the Factory into the Creator class instead of expressing it using an abstract method?
Why not composing the Factory into the Creator class instead of expressing it using an abstract method?
Because in that case the client "knows" what Factory class to instantiate which defeats the whole purpose of the pattern. The whole idea is that the client is oblivious as what factory is built, it only makes a call to an Abstract class. Think that you plugin-in to your framework some third party factory provider and you have no idea what they instantiate (and also don't care) as long as serves the purpose.
The Factory Method Pattern is used to give subclasses control over the type of object they generate. In your case, it is not the subclass that controls the type of object but the user of the class.
The following example is copies from the Wikipedia entry on the Factory Method Pattern. We have a maze game which exists in two variants: the normal maze game and a magic maze game with adapted rules. The normal maze game consists of normal rooms and the magic maze game of magic rooms.
public class MazeGame {
public MazeGame() {
Room room1 = makeRoom();
Room room2 = makeRoom();
room1.connect(room2);
this.addRoom(room1);
this.addRoom(room2);
}
protected Room makeRoom() {
return new OrdinaryRoom();
}
}
public class MagicMazeGame extends MazeGame {
#Override
protected Room makeRoom() {
return new MagicRoom();
}
}
By using the Factory Method Pattern we can make sure that the MagicMazeGame consists of MagicRooms but we can still re-use parts of the superclass.
In your suggestion the MazeGame class would be changed to:
public class MazeGame {
public MazeGame(RoomFactory factory) {
Room room1 = factory.makeRoom();
Room room2 = factory.makeRoom();
room1.connect(room2);
this.addRoom(room1);
this.addRoom(room2);
}
}
and now it would be possible to do:
MazeGame game1 = new MazeGame(new MagicRoomFactory());
MazeGame game2 = new MagicMazeGame(new OrdinaryRoomFactory());
which is something you would like to prevent because then MazeGames with the wrong kind of rooms in it can be created.
its often useful in these types of situations to use actual English types for illustrations rather than more abstract terms like "Product"
So, let's take Pets, and say that every (sub-)type of Pet has a Home (eg. Dog has a Kennel).
For your example, we would have :
Public void doStuff() {
Home home = factory.createHome();
}
But in this case, where does the logic go that says Dogs get Kennels, and Birds get Cages? It would have to go in the factory object - which in turns means that the inheritance hierarchy of Pets would have to be explicitly repeated in the Factory logic. This in turn means that every time you add a new type of Pet, you'll have to remember to add that type to the Factory as well.
The factory method pattern means that you'd have something like :
public class Pet {
private String name;
private Home home;
public Pet(String name) {
this.name = name;
this.home = this.createHome();
}
public abstract Home createHome();
This allows that every time you create a new type of Pet, you can specify that Pet type's home without having to change any other class, and in the process also know that every Pet type DOES have a Home.
Eg. You would have :
public class Dog extends Pet {
public Home createHome() {
return new Kennel();
}
}
Edited to add Dog example
I think that the answers to this question aren't totally satisfactory, so here's my two cents...
To quote #Hoopje's answer, we might end up with something like this:
public class MazeGame {
public MazeGame(RoomFactory factory) {
Room room1 = factory.makeRoom();
Room room2 = factory.makeRoom();
room1.connect(room2);
this.addRoom(room1);
this.addRoom(room2);
}
}
and then
MazeGame game1 = new MazeGame(new MagicRoomFactory());
MazeGame game2 = new MagicMazeGame(new OrdinaryRoomFactory());
As has been discussed above, this is nonsensical. However, I would contend that those last two lines don't make sense anyway, because in the OP's opinion, you would never need to create a MagicMazeGame at all. Instead you would just instantiate a MazeGame passing in new MagicRoomFactory().
MazeGame magicOne = new MazeGame(new MagicRoomFactory());
MazeGame normalOne = new MazeGame(new OrdinaryRoomFactory());
However, let's imagine that our MazeGame has multiple factories. Let's say that as well as needing to have a room factory, it also needs to have a points factory, and also a monsters factory. In this situation, we might end up with all of this being forced into the MazeGame constructor, like this:
public MazeGame(RoomFactory rmFactory, PointsFactory pointsFactory, MonsterFactory monstersFactory)
This is fairly convoluted, and instead it would be better to create concrete subclasses that each control their own type of game. That long constructor looks like a code smell to me too, though someone more knowledgeable might be able to add to this.
What's more, this means that whichever object is instantiating the game has to know about all of these inner-working classes, which breaks encapsulation.
All in all, by doing it this way we are giving too much control to the client, who doesn't want to know about all of these implementation details.
That's how I see it anyway...

Understanding Abstract Factory pattern

I've read about abstract factory patter on wiki. But I don't understand really profit by using this pattern. Can you get an example in which is hard to avoid abstract factory pattern. Consider the following Java code:
public abstract class FinancialToolsFactory {
public abstract TaxProcessor createTaxProcessor();
public abstract ShipFeeProcessor createShipFeeProcessor();
}
public abstract class ShipFeeProcessor {
abstract void calculateShipFee(Order order);
}
public abstract class TaxProcessor {
abstract void calculateTaxes(Order order);
}
// Factories
public class CanadaFinancialToolsFactory extends FinancialToolsFactory {
public TaxProcessor createTaxProcessor() {
return new CanadaTaxProcessor();
}
public ShipFeeProcessor createShipFeeProcessor() {
return new CanadaShipFeeProcessor();
}
}
public class EuropeFinancialToolsFactory extends FinancialToolsFactory {
public TaxProcessor createTaxProcessor() {
return new EuropeTaxProcessor();
}
public ShipFeeProcessor createShipFeeProcessor() {
return new EuropeShipFeeProcessor();
}
}
// Products
public class EuropeShipFeeProcessor extends ShipFeeProcessor {
public void calculateShipFee(Order order) {
// insert here Europe specific ship fee calculation
}
}
public class CanadaShipFeeProcessor extends ShipFeeProcessor {
public void calculateShipFee(Order order) {
// insert here Canada specific ship fee calculation
}
}
public class EuropeTaxProcessor extends TaxProcessor {
public void calculateTaxes(Order order) {
// insert here Europe specific tax calculation
}
}
public class CanadaTaxProcessor extends TaxProcessor {
public void calculateTaxes(Order order) {
// insert here Canada specific tax calculation
}
}
If we need to just create objects in a code below 1-2 times in a code then we can use just new operator. And why we need in abstract factory?
You are missing half of the work :)
void processOrder(FinancialToolsFactory ftf,Order o) {
tft.createTaxProcessor().calculateTaxes(o);
tft.createShipFeeProcessor().calculateShipFee(o);
}
this code works as well as you pass a canadian or european implementation of FinancialToolsFactory (you can externalize the implementor class to external resource and instantiate with a Class.newInstance(), for example).
In this case one of the real benefits of pattern usage is not writing the code that implements the pattern, but who use that code!
PS: My answer is intentionally incomplete and try to answer just this specific question; a discussion about pattern and their benefits is too big!
You'd take advantage of this pattern if you were to support different implementations transparently. By delegating the decision of which implementation to use to the factory, you have a single point in your code where that decision is made (a.k.a. single responsibility).
The abstract factory pattern takes this concept beyond by aggregating related factories, such as different financial tools factories in your sample.
Now, if you only instantiate your financial tools once or twice in your code, using factories is over-engineering. The gain comes when you need to instantiate different implementations of the same interfaces in different places many times and you want to be able to work without worrying about which implementation you are using or how that decision is made.
There are quite some resources about this pattern on the web, and it's hard to guess what might be the best way of explaining its purpose in a way that sounds "plausible" for you.
But I think that the key point is:
With this pattern, someone who wants to create an instance of a particular implementation of an interface does not need to know what this particular implementation is. The call to the new operator is hidden inside the factory, and the user of the factory does not need to know the concrete class.
This makes it easier to switch the implementation later: You don't have to find and adjust all places where new ConcreteClass() was called and change it to new OtherConcreteClass() in order to use a different implementation. You just pass a different factory around, and everybody who uses this factory automatically creates instances of OtherConcreteClass (without even knowing that he does so...)

instantiate a specific subtype depending on the constructor argument

I've the case that I have four types of data objects:
class DataTypeAlpha extends DataType
class DataTypeBeta extends DataType
class DataTypeGamma extends DataType
class DataTypeDelta extends DataType
and four different TreeNode types from the GUI framework, each one specific to the wrapped DataType:
class AlphaTreeNode extends MyAppTreeNode
...
Now I often have the pattern that I have an instance of DataType and need a new instance of MyAppTreeNode. I see two solutions. Solution one:
class DataType {
// Instantiates and returns the appropriate MyAppTreeNode for this DataType
abstract MyAppTreeNode createTreeNode();
}
Solution two:
class MyAppTreeNode {
static MyAppTreeNode createTreeNodeForDataType(DataType dataType) {
if(dataType instanceOf DataTypeAlpha) return new AlphaTreeNode((DataTypeAlpha)dataType)
else if (dataType instanceOf DataTypeBety) return new BetaTreeNode((DataTypeBeta)dataType)
else if ...
else if ...
else throw new IllegalArgumentException();
}
}
Solution one uses polymorphism, is shorter and more "elegant". But I'd prefer that the DataType classes have no knowledge about the GUI framework that I use. Maybe I could even use two different GUI frameworks?
Do you see a third solution? I added the Guice tag to this question. Maybe there is some function in Guice or another dependency injection library that could help here?
Looking through similar questions:
Of course I will use the Factory Pattern for this, but inside the factory I'm still left with the question.
You might use a visitor inspired approach for this. As usual all DataType objects has an accept method, but as opposed to the normal visitor pattern, it does not traverse children and it will return a value. To avoid too much confusion, lets call object passed to accept for an operator instead of visitor. The trick is to make accept and operators return a generic type.
So the code will be something like this in the data model
public abstract class DataType {
public abstract <T> T accept(Operator<T> op);
}
public interface Operator<T> {
T operateAlpha(DataTypeAlpha data);
T operateBeta(DataTypeBeta data);
...
}
public class DataTypeAlpha extends DataType {
public <T> T accept(Operator<T> op) {
return op.operateAlpha(this);
}
}
....
and in the GUI you will have
public class TreeNodeFactory implements Operator<MyAppTreeNode> {
public MyAppTreeNode operateAlpha(DataTypeAlpha data) {
return new AlphaTreeNode(data);
}
...
}
public class MyAppTreeNode {
static TreeNodeFactory factory = ...;
static MyAppTreeNode createTreeNodeForDataType(DataType dataType) {
return dataType.accept(factory);
}
}
So the short, simple answer is that a constructor can only return its own type. No subtypes, no other classes, no reused instances, no null—only a new instance of that type. So you're looking for a solution that operates outside the confines of a constructor here. The simplest and most common workaround is to write a static factory method (usually named newInstance or getInstance) which returns any new or existing instance of the enclosing class and can return a subclass or null without trouble.
Your points about your solution 1 and 2 are valid. It'd be great to avoid making the data types aware of the UI, and in your situation (with only four types) I'd probably opt for your solution 2. If you have operations that will vary among those types—which is a pretty common requirement in a GUI that puts a mixture of types into a tree—Bittenus's solution is probably worth it. (It's a lot of code to handle if you only need to do this sort of thing once.)
If you somehow expect your type count to grow but your operations to never grow, one alternative is to extract the polymorphic creation into a separate Factory, which might look like this:
class MyAppTreeNode {
interface Factory {
MyAppTreeNode create(DataType type);
}
}
class AlphaTreeNode extends MyAppTreeNode {
static class Factory implements MyAppTreeNode.Factory {
#Override public AlphaTreeNode create(DataType type) {
// Remember, in an override your return types can be more-specific
// but your parameter types can only be less-specific
return new AlphaTreeNode((DataTypeAlpha) type);
}
}
}
Then you can just make a map (though consider Guava's ImmutableMap for better semantics):
private static Map<Class<?>, MyAppTreeNode.Factory> factoryMap = new HashMap<>();
static {
factoryMap.put(DataTypeAlpha.class, new AlphaTreeNode.Factory());
// ...
}
public static createTreeNode(DataType type) {
return factoryMap.get(type.getClass()).create(type);
}
More trouble than it's worth? Probably, in most cases. But bear in mind that it's probably the best that Guice can get you, as well. Guice has some ability to auto-generate the Factory implementation for you, but you'll still need to map DataType to MyAppTreeNode.Factory one way or another, and it's going to have to live in a Map, a conditional, or the double indirection that powers the Visitor pattern.
Hope this helps, if only to endorse the answers you already have!

Categories

Resources