Patterns of Object-Oriented PHP: Factory Approach

Keywords: PHP

Factory Method Model

Object-oriented design emphasizes that abstract classes are superior to practice, and tries to generalize code design as much as possible, rather than specialize it - that is, to reduce coupling and improve standardization. Therefore, the predecessors have designed the factory method of "specific class processing instantiation".

problem

The Appointment class needs to parse the BloggsCal data format. Within the class, we write the data format to BloggsCal, which will cause coupling, and in fact, business needs will face more data formats in the future.

Realization

At this time, we introduce the factory method mode, and set up CommsManager class (creator), ApptEncoder class (Product).

Next, users only need to call the getApptEncoder method of the CommsManager object to get the object they need without paying attention to the data format of the object.

abstract class ApptEncoder {
    abstract function encode();
}

class BloggsApptEncoder extends ApptEncoder {
    function encode()
    {
        return "The data format is BloggsCal. ";
    }
}

class MegaApptEncoder extends ApptEncoder {
    function encode()
    {
        return "The data format is MegaCal. ";
    }
}

class CommsManager {
    const BLOGGS = 1;
    const MEGA = 2;
    private $mode = 1;

    function __construct( $mode ) {
        $this->mode = $mode;
    }

    function getApptEncoder() {
        switch ( $this->mode ) {
            case ( self::MEGA ) :
                return new MegaApptEncoder();
            default:
                return new BloggsApptEncoder();
        }
    }

    function getHeaderText() {
        switch ( $this->mode ) {
            case ( self::MEGA ):
                return "Mega Format header";
            default:
                return "BloggsCal Format header";
        }
    }

    function getFootText() {
        switch ( $this->mode ) {
            case ( self::MEGA ):
                return "Mega Format footpages";
            default:
                return "BloggsCal Format footpages";
        }
    }
}

$comms = new CommsManager( CommsManager::MEGA );
$apptEncoder = $comms->getApptEncoder();
echo $apptEncoder->encode();

Notice the three getXXX methods of the CommsManager class?

Once data formats increase, functions increase, and business differences exist between data formats, a new problem will arise: a large number of judgment statements, which some people, including myself, believe are symbols of code corruption.

At least, we should not be optimistic when duplicate code starts to spread. (This error is repeated to some extent, despite the following treatment.)

Faced with the above problems, we have the following three requirements:

  1. Only when the code runs can we understand the type of object we want to generate (real-time reference, note the sentence: $comms = new CommsManager (CommsManager:: MEGA));

  2. Relatively easy to add new data format (Product);

  3. Customization can be easily added to each product type.

In that case, we simply stripped the data formats from CommsManager to form separate subclasses.

// Product Abstract class, subclass code, ibid.

abstract class CommsManager {
    abstract function getApptEncoder();
    abstract function getHeaderText();
    abstract function getFooterText();
}

class BloggsCommsManager extends CommsManager {
    function getApptEncoder() {
        return new BloggsApptEncoder();
    }

    function getHeaderText() {
        return "BloggsCal Format header";
    }

    function getFooterText() {
        return "BloggsCal Format footpages";
    }
}

class MegaCommsManager extends CommsManager {
    function getApptEncoder() {
        return new MegaApptEncoder();
    }

    function getHeaderText() {
        return "MegaCal Format header";
    }

    function getFooterText() {
        return "MegaCal Format footpages";
    }
}

$comms = new BloggsCommsManager();
$apptEncoder = $comms->getApptEncoder();
echo $apptEncoder->encode();

Result

This meets the three requirements mentioned above, but I think you've noticed cleverly that, to a certain extent, the creators / products have duplicated the code. Moreover, the problem has been shifted to the factory method. We are only dealing with the Appointment function at present. What if we add the TodoList function?

The answer is obvious: we need an architecture that can handle a set of related implementations at the same time, and the solution is in the next article: the abstract factory pattern.

Posted by wizhippo on Sat, 20 Apr 2019 14:24:35 -0700