3

I have read about a factory pattern and I wonder if it is compatible with the Open-Closed Solid Principle. In many examples a factory method takes enum and then in the switch statement creates a concrete object, please see C# example on the wiki page. It sounds reasonable that I might want to decide which object should be created based on enum. On the other hand, when enum is extended I also have to add a new case in the switch statement which breaks Open-Closed Solid Principle.

I also wonder if the wiki page really describes a factory method pattern or something which is called a simple factory. I can create the following interface:

public interface IPersonFactory
{
    IPerson CreatePerson();
}

and then implement a concrete factory, for example:

public class VillagerFactory : IPersonFactory
{
    public IPerson CreatePerson()
    {
        return new Villager();
    }
}

Then based on enum I can decide which factory implementation should be used but again when enum is extended I also have to add a case in the switch statement somewhere in the code so I'm not sure if the second approach is better.

Could you please clarify it ?

Claudio
  • 10,614
  • 4
  • 31
  • 71
Irbis
  • 1,432
  • 1
  • 13
  • 39
  • I've explained the Factory patterns to the best of my ability in [What are the differences between Abstract Factory and Factory design patterns?](https://stackoverflow.com/a/50786084/1371329) – jaco0646 May 14 '19 at 02:05

2 Answers2

1

GoF’s Factory Method pattern has nothing to do with enum and in fact is very compatible with the Open-closed Principle.

Let’s say you are coding a class C. At some code inside C, you use the new keyword to create objects of some class X.

Later, you need to reuse class C somewhere, but with customization. The only needed customization is that inside C you want to create objects of some derived class of X, say X'.

Then you apply the Factory Method pattern by making the class C more abstract: add an abstract method with signature returning an object of type X, replace every call to new X by the call to the abstract method. The rest code of class C is untouched.

We call that abstract method Factory Method.

Now you can reuse the class C somewhere: write class C' inheriting C, implement the abstract method, let it create (typically with the new keyword) and return an object of whatever type X, X', X'' you want.

As you can see, the class C is open: it leaves the room for extension with the abstract method. It is closed: its source code does not need to be modified.

Developing software by adding more classes, not by (or rarely by) modifying existing classes. That’s the vision of OOP.

Nghia Bui
  • 3,694
  • 14
  • 21
0

The factory pattern has many uses. I'll give brief description of them and their uses with very simple examples.

NOTE: The examples have only illustrational purpose, so some of them may seem like an overkill other may not seem like a good solution to the problem. Giving realistic example for everything is hard, so I'll give myself some freedom here by ignoring some principles for illustrational purposes

Problem: You have a class that has many constructors with different parameters. This makes the code hard to read, write and reason about.

Solution: Create a factory that simplifies the creation of objects and makes the code cleaner by having multiple well named methods.

Example: You have a system that has many different types of products.

public enum ProductType { Book, Paper, Pen }

public class Product {
    public ProductType Type { get; set;}
}

public class ProductFactory {
    public Product CreateBook() { return new Product(ProductType.Book); }
    public Product CreatePaper() { return new Product(ProductType.Paper); }
    public Product CreatePen() { return new Product(ProductType.Pen); }
}

Problem: You have an object that is created from different input and/or by having to process this input. Or you have an object that has complex creational process.

Solution: Create a factory that does this for you with well named methods.

Example: You have a system that processes files from the file system and uses their extensions for complex operations. You want to use FileExtension class to handle equality (in Windows is case insensitive) and other operations so you can avoid having floating strings around , avoid having bugs from case insensitive comparison and make maximum use of strong typing

public class FileExtension { }

public class FileExtensionFactory {

    public FileExtension Create(string extension) {
        return new FileExtension(extension);
     }

    public FileExtension FromPath(string fullPath) {
        return new FilePath(Path.GetExtension(fullPath);
     }
}

public class SomeClassThatUsesTheFactory {

    public void DoSomethingWithFileExtension(string filePath) {
        var extension = FileExtensionFactory.FromPath(filePath);
        // do something with the extension
    }
}

Here you can see that the usage of the FromPath method makes the code cleaner and more readable. It also hides the way that filePath parameter is parsed and avoids duplication of the parsing code every time you need to create an extension from filePath.

Problem: You need to create instances of a family of related objects that plug-in to your system.

Solution: Use abstract factory design pattern.

Example: You are building an ORM and you want to support different types of databases. You want to define an interface for database connections that your ORM code will use. Later you want to be able to setup your ORM with different types of connections so you can connect to different databases. You want to be able to add support for more databases to your ORM.

public interface IDbCommand : IDiposable {
   string CommandText { get; set; }
   void Execute();
}

public interface IDbConnection : IDisposable {

   void Open();
   void Close();

   IDbCommand CreateCommand();
   IDbTransaction BeginTransaction();

   // other stuff
}

public interface IDbConnectionFactory {   
   IDbConnection CreateConnection();
}

public class MySqlCommand : IDbCommand { }
public class MySqlConnection : IDbConnection { }
public class MySqlConnectionFactory : IDbConnectionFactory { }

public class PostgreCommand : IDbCommand { }
public class PostgreConnection : IDbConnection { }
public class PostgreSqlConnectionFactory : IDbConnectionFactory { }

public class OrmSession {

   public OrmSession(IDbConnectionFactory) { }
}

Here we see the Open-Closed principle in action. You ORM will use the abstract factory, so you can provide a concrete factory. You can do this from your code, use a configuration file or use ServiceLocator or DI to inject a concrete factory.

Notice also something interesting here. IDbConnection also provides a CreateCommand FactoryMethod. Each connection will need to create a concrete command, so it provides a method for this even if it's not a pure factory.

There are other situations in which you can use factories. Testing if one of them. You may need to provide an Abstract Factory so you can make parts of your app testable.

As a conclusion, the Factory pattern has many uses. They can vary from just making the code cleaner and more expressive to achieving the Open-Closed principle. The driving force here is the problem that you have. You have problems with object creation. Can a factory solve your problem?

Not always. Sometimes the creation of object is so complex and has many different variations that a Factory doesn't help and can make things messy. Sometimes a constructor or two is all you need.

In case of complex objection creation, you can use the BuilderPattern with or without FluentInterface.

expandable
  • 2,180
  • 7
  • 15
  • None of these examples resemble GoF patterns. – jaco0646 May 14 '19 at 12:47
  • Why should it? Is the GOF the only factory pattern out there? How you do classify IDbConnectionFactory interface then? It's exactly as defined in the GOF book. It defines an interface for creating family of related objects. If not a factory so what is it? IDbConnection.CreateCommand() is exactly factory method from GOF book. Besides the question is about how the factory pattern relates to Open-Closed Principle. If we follow only the GOF that means that a builder with a FluentInterface is not a builder because in the book doesn't use this implementation. – expandable May 14 '19 at 13:00
  • I see.To me the concept of "canonical" things in programming is flawed. A pattern is just a guideline on how to resolve a specific problem in a specific context. The implementations and diagrams in the GOF book are used for example purposes to clarify a concept not to be used as rules or laws. Since our problems are different all the time having "canonical" example cannot apply and trying to do so get's people in bad sittuations. Take for example the observer pattern. I've seem many different implementations and only few of them match the one from the GOF book. – expandable May 14 '19 at 14:06
  • Your right. It's a vocabulary. It's not the diagram of a pattern that created the pattern it's the purpose of a pattern. Every object that has a method that returns another object is indeed a pattern. It's called a Factory Method and is part of the GOF book. Objects that are used only for creating other objects are called Factories and they contain only Factory Methods. The concrete structure of the object or it's methods doesn't matter. Method creates object -> FactoryMethod. Object has only FactoryMethods -> Factory. If people call them with these concepts they are right to do so – expandable May 14 '19 at 14:34
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/193331/discussion-between-jaco0646-and-expandable). – jaco0646 May 14 '19 at 14:51