7
\$\begingroup\$

Can you please verify my approach?

using System;

    /*
    * In Factory pattern, we create object without exposing the creation logic. 
    * In this pattern, an interface is used for creating an object,
    * but let subclass decide which class to instantiate.
    * */


namespace FactoryMethod
{

Product (abstract)

    /*
    * Faza Class ITree
    *
    * */
    public interface ITree
    {
        string GetTreeName();
    }

Products (concrete)

    /*
    * The Concrete class which implements ITree
    * 
    * */

    public class BananaTree : ITree
    {
        public string GetTreeName()
        {
            return "My Name Is Banana Tree";
        }
    }

    /*
    * The Concrete class which implements ITree
    * 
    * */
    public class CoconutTree : ITree
    {
        public string GetTreeName()
        {
            return "My Name Is Coconut Tree";
        }
    }

Factory (abstract)

    /*
    * Faza Class TreeType 
    * If you want you can add abstract class instad of faza class
    *
    * */
    public interface TreeType
    {
        ITree GetTree(string tree);
    }

Factory (concrete)

    /*
    * Concrete class which implements faza or concrete class
    *
    * */
    public class ConcreteTreeType : TreeType
    {

        public ITree GetTree(string tree)
        {

            if (tree == "COCONUT")
                return new CoconutTree();
            else
                return new BananaTree();

        }
    }

Client code

    /*
    * main app.
    * 
    *  */
    class Program
    {
        static void Main(string[] args)
        {
            TreeType oTreeType = new ConcreteTreeType();

            ITree banana = oTreeType.GetTree("COCONUT");
            Console.WriteLine(banana.GetTreeName());

            Console.ReadKey();
        }
    }
}
\$\endgroup\$
  • \$\begingroup\$ You can also choose to use exceptions to make it more robust. Like in your code anyone can ask for "Rose" tree and still get banana tree. \$\endgroup\$ – wayfare Apr 28 '14 at 15:13
10
\$\begingroup\$

I personally would not rely on using magic strings.

Magic strings are where you have taken something like a class/method/variable name and written it within a string, which is then used to identify the appropriate class/method/variable

This makes it hard to refactor later on if you change a class name, it is too easy to miss instances etc. Furthermore, the code that you currently have is case-sensitive. This might be by design, however, consider the following:

var actuallyABananaTree = oTreeType.GetTree("Coconut");

Even though the developer is specifying a coconut tree, he actually gets a banana tree. If the construction logic was changed to:

if (tree.Equals("coconut", StringComparison.OrdinalIgnoreCase))

You would then get the right tree type back. See StringComparison Enum for the comparison options.

In that same construction logic, you are also not checking to see whether or not the parameter tree is a null reference. This might be something that you wish to consider adding, especially if you use the approach suggested above.

Use of Enums

A better approach would be to use enums instead of magic strings. For example:

enum MyTreeTypes {
      Coconut,
      Banana
}

Then in your construction logic, you can have:

public ITree GetTree(MyTreeTypes tree)
{
    switch (tree)
    {
        case MyTreeTypes.Coconut:
            return new CoconutTree();
        default:
            return new BananaTree();
    }
}

Using this approach ensures type safety and prevents problems of magic strings when refactoring etc. Also, you will compile time errors if you spell the tree type incorrectly

\$\endgroup\$
  • \$\begingroup\$ Hi @Stuart Blackler, thanks for your reply. my doubt is instead of abstract class I’ve used faza class. is it creates any issue? ,, regd. enum i agree with your point. \$\endgroup\$ – Thava Apr 28 '14 at 4:21
  • 1
    \$\begingroup\$ +1 excellent point. I'd call the enum type TreeType though (singular), and find another name for the abstract factory interface. \$\endgroup\$ – Mathieu Guindon Apr 28 '14 at 13:41
  • \$\begingroup\$ @Mat'sMug I agree, that's what I would normally do. I try and steer clear of changing variable names in reviews and stick with what the OP has as it will correlate better for them, imo. :) \$\endgroup\$ – Stuart Blackler Apr 28 '14 at 15:11
  • \$\begingroup\$ Good point. Don't forget that bad naming can be part of a fruitful peer review - feel free to join us in The 2nd Monitor/Code Review Chat ;) \$\endgroup\$ – Mathieu Guindon Apr 28 '14 at 15:27
4
\$\begingroup\$

This pattern looks very much like a creational pattern called Abstract Factory.

What's nice about design patterns, is that they're a very effective mean of communication with fellow programmers; provided that they know the patterns, when you say TreeFactory it should be clear what the type is for.

You've called your abstraction TreeType, which is less clear. The naming you're using makes things quite confusing, especially in the client code - compare this:

TreeType oTreeType = new ConcreteTreeType();

ITree banana = oTreeType.GetTree("COCONUT");
Console.WriteLine(banana.GetTreeName());

To this:

ITreeFactory factory = new CoconutTreeFactory();

ITree tree = factory.Create();
Console.WriteLine(tree.GetTreeName());

In C# it's common practice to name interface starting with a capital i, so this:

public interface TreeType
{
    ITree GetTree(string tree);
}

I'd write like this:

public interface ITreeFactory
{
    // follow @Stuart's advice here, don't rely on magic strings!
    ITree Create(TreeType treeType);
 }

TreeType would be a much better name for an enum type (enum names should be singular):

public enum TreeType
{
    Banana,
    Coconut,
    Apple,
    Orange
}

What you have here, however, isn't quite exactly an abstract factory, because the client code, despite working against an ITree, knows exactly what type he's getting... which is weird:

abstract factory actors

The client code can know about ITreeFactory and ITree, but the point of an abstract factory is that he doesn't need to know/care about the exact implementation of ITree that the factory is producing, so your client code can be provided with an ITreeFactory and call its Create() method to get an ITree - whatever implementation that is.

If the client code needs to use the same abstract factory to create multiple instances of different ITree implementations, then I'd go with a generic abstract factory:

public interface ITreeFactory<TTree> where TTree : ITree
{
    ITree Create<TTree>();
}

If TTree has a parameterless constructor, you can add a generic type constraint to ensure TTree always has a default constructor, and implement a generic concrete factory class like this:

public class TreeFactory<TTree> : ITreeFactory<TTree> 
    where TTree : ITree, new()
{
    public ITree Create<TTree>()
    {
        return new TTree();
    }
}

That can be called like this:

ITree appleTree = factory.Create<AppleTree>();
ITree orangeTree = factory.Create<OrangeTree>();

I don't like this very much though, because it allows the client code to control the exact implementation type he's getting out of the factory - this smells of Control Freak, a Dependency Injection Anti-Pattern... but sometimes it's just what's needed.


If TTree doesn't have a parameterless constructor, then the generic concrete factory has a problem:

public class TreeFactory<TTree> : ITreeFactory<TTree> 
    where TTree : ITree
{
    public ITree Create<TTree>()
    {
        return new ????(); // so, what type is TTree? how do we pass ctor parameters?
    }
}

That can't work! This is where the enum type kicks in, when the type of the factory's product is unknown at compile-time - now because each tree type might have different constructor arguments, abstracting them into their own type can simplify things:

public class TreeFactory : ITreeFactory
{
    private readonly IDictionary<TreeType, Func<ITreeArgs,ITree>> _create;

    public TreeFactory(IDictionary<TreeType, Func<ITreeArgs,ITree>> factoryMethods)
    {
        _create = factoryMethods;
    }

    public ITree Create(TreeType treeType, ITreeArgs args)
    {
        return _create[treeType](args);
    }
}

Where ITreeArgs could perhaps encapsulate an object that merely exposes an array of constructor arguments, whatever they are. Notice that the factory class itself doesn't even know/care how each TreeType gets created - it receives a dictionary of factory methods (one for each TreeType) and simply calls into it in the Create method; this means if you want to modify how this factory class generates such or such ITree implementation, you don't even need to change the factory class's code!

This is probably overkill for your example code however, since all your ITree implementations seem to have a default constructor, therefore the generic factory would work.


It's often best to leave the client code oblivious of implementation details:

public class ClientObject
{
    private readonly ITreeFactory _factory;

    public ClientObject(ITreeFactory factory)
    {
        _factory = factory;
    }

    public void DoSomething()
    {
        var tree = _factory.Create();
        Console.WriteLine(tree.Name); // assuming a "Name" property on `ITree` here
    }
}    

All ClientObject knows, is that he's getting an ITree. The exact implementation type is completely irrelevant, and ClientObject is completely decoupled from any specific ITree and ITreeFactory implementations.

From the very first comment at the top of your code, I believe this is what you're trying to achieve.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.