Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is my factory an anti-pattern?

Tags:

oop

php

I saw this code on a different question - 2nd answer link and the first comment was that it is a static factory anti-pattern and that it violates SRP:

class User {
    public static function create($userid) {
        // get user from the database

        // set $isPartner to true or false
        // set $isClient to true or false
        // set $isModerator to true or false

        if ($isPartner) {
            return new Partner($userid);
        } elseif ($isClient) {
            return new Client($userid);
        } elseif ($isModerator) {
            return new Moderator($userid);
        } else {
            return new User($userid);
        }
    }
}

$person = User::create($userid);

Now I can understand why it violates SRP - because it deals with connecting to the database as well as building the new class, but besides that I'm not sure if I understand why it is an anti-pattern.

I wanted to write a bit of code that seemed quite similar to this so I am now wondering whether to avoid it, this is my code (in pseudo-code):

class DatabaseClass()
{
...deals with getting a result from the database...
}

abstract class User()
{
...base class for all users...
}

class AdminUser extends User(){}
class StaffUser extends User(){}
class BasicUser extends User(){}

class UserFactory()
{
    function createUser($privilege)
    {
        if($privilege=="high")
            return new AdminUser($privilege);
        else if($privilege=="med")
            return new StaffUser($privilege);
        else
            return new BasicUser($privilege);
    }

$db=new DatabaseClass($username,$password);
$result=$db->getUser();
$userfactory=new UserFactory();
$user=$userfactory->createUser($result);

Now at the moment I am not using a static method but would my oop still be considered an anti-pattern?

Especially since I don't really see any difference in then doing something like this instead and it being pretty much the same thing:

$result=DatabaseClass::getUser($username,$password);
$user=UserFactory::createUser($result);
like image 364
mrmryb Avatar asked Jan 24 '13 15:01

mrmryb


People also ask

Is factory an anti-pattern?

The Factory Pattern is an Anti-Pattern So is Singleton, and it's an anti-pattern.

How do you identify anti patterns?

In an organization, there are three main opportunities to identify anti-patterns: During design reviews, during code reviews and during refactoring of legacy code. Design reviews are a great opportunity to find anti-patterns.

What is an example of an anti-pattern?

Poltergeist. A poltergeist is an anti-pattern involving a pointless class that is used to call methods of another class or simply adds an unnecessary layer of abstraction.

What type of design pattern is factory?

The factory method is a creational design pattern, i.e., related to object creation. In the Factory pattern, we create objects without exposing the creation logic to the client and the client uses the same common interface to create a new type of object.


2 Answers

No, it's not an anti-pattern. Personally, I take the term "anti-pattern" with a grain of salt whenever I see it. It's far too easily tossed around by people who don't like your code but can't really articulate why.

The problem with a static factory is that any class which uses the factory must explicitly depend on it. That violates the principle that we should depend on abstractions rather than concretions (the 'D' in SOLID). This makes code using the factory harder to re-use and unit test. But keep in mind that the approach has benefits too. It's easier to write and easier to understand.

Your code is equivalent to a static factory method. The problem in both cases is that the caller must know the concrete class of the factory.

like image 103
Peter Ruderman Avatar answered Oct 14 '22 07:10

Peter Ruderman


Your factory is not the issue, is the conection to the db i guess. Other than that, you're using the factory method well.

Upon seen the edit, its for the best that you separate the data access from the factory. It's not so much an "anti-pattern" as a bad idea from the maintenance perspective.

I would still be ok (not so good but still ok) if you had your data access code inside the factory as long as that code was in a separate class (that is reused across the application for data access) and you just call it to get something you need. In that case it'd be a combination of two patterns, a factory and a facade.

What i'd really pay attenntion to is to find out if the data isn't going to change during the session, if so just go one time to the db an keep the results. If you only create the User (or derived classes) once, make damm sure you only do it once.

That i think is more important that respecting patterns blindly.

like image 42
Carlos Grappa Avatar answered Oct 14 '22 09:10

Carlos Grappa