Upgrade to Pro — share decks privately, control downloads, hide ads and more …

OOP & Design Patterns (Part 1 + Part 2)

Michael C.
December 04, 2018

OOP & Design Patterns (Part 1 + Part 2)

Michael C.

December 04, 2018
Tweet

More Decks by Michael C.

Other Decks in Programming

Transcript

  1. Dependency Injection Dependency Injection is where components are given their

    dependencies through their constructors, methods, or directly into fields. Those components do not get their dependencies themselves, or instantiate them directly. — picocontainer.com/injection.html
  2. Dependency Injection Container A dependency injection container is an object

    that enables to standardize and centralize the way objects are constructed and configured in an application. — symfony.com
  3. Object Composition In computer science, object composition is a way

    to combine simple objects or data types into more complex ones. — wikipedia.com
  4. Single Responsibility A class should have one, and only one,

    reason to change. — Robert C. Martin
  5. Open Closed Principle You should be able to extend a

    classes behavior, without modifying it. — Robert C. Martin
  6. Object Calisthenics Calisthenics are gymnastic exercises designed to develop physical

    health and vigor, usually performed with little or no special apparatus. — dictionary.com
  7. 1. One level of indentation per method 2.Don’t use the

    ELSE keyword 3.Wrap primitive types and strings 4.Two instance operators per line 5.Don’t abbreviate 6.Make short and focused classes 7. Keep number of instance properties low 8.Treat lists as custom collection objects 9.Avoid public accessors and mutators
  8. • 5 lines per method • 100 lines per class

    • 15 classes per namespace
  9. class Invoice { // ... private $payments; public function __construct(…)

    { // ... $this->payments = new ArrayCollection(); } public function collectPayment(Payment $payment): void { // ... $this->payments->add(new CollectedPayment( $payment->getReceptionDate(), $amount, $payment->getSource() // wire, check, cash, etc. )); } }
  10. Filtering the collection class Invoice { // ... public function

    countPaymentsReceivedAfterDueDate(): int { return $this ->payments ->filter(function (CollectedPayment $payment) { return $payment->getReceptionDate() > $this->dueDate; }) ->count(); } }
  11. Custom Collection Type class CollectedPaymentCollection extends ArrayCollection { public function

    receivedAfter(\DateTimeImmutable $origin): self { $filter = function (CollectedPayment $payment) use ($origin) { return $payment->getReceptionDate() > $origin; }; return $this->filter($filter); } }
  12. class Invoice { // … public function __construct(…) { //

    ... $this->payments = new CollectedPaymentCollection(); } public function countPaymentsReceivedAfterDueDate(): int { return $this ->payments ->receivedAfter($this->dueDate) ->count(); } }
  13. class Invoice { private $number; private $billingEntity; private $issueDate; private

    $dueDate; private $dueAmount; private $remainingDueAmount; public function __construct( InvoiceId $number, BillingEntity $billingEntity, Money $dueAmount, \DateTimeImmutable $dueDate ) { $this->number = $number; $this->billingEntity = $billingEntity; $this->issueDate = new \DateTimeImmutable('today', new \DateTimeZone('UTC')); $this->dueDate = $dueDate; $this->dueAmount = $dueAmount; $this->remainingDueAmount = clone $dueAmount; } }
  14. Issue an Invoice $invoice = new Invoice( new InvoiceId('INV-20180306-66'), new

    BillingEntity('3429234'), new Money(9990, new Currency('EUR')), new \DateTimeImmutable('+30 days') );
  15. class Invoice { // ... private $overdueAmount; private $closingDate; private

    $payments = []; public function collectPayment(Payment $payment): void { $amount = $payment->getAmount(); $this->remainingDueAmount = $this->remainingDueAmount->subtract($amount); $this->overdueAmount = $this->remainingDueAmount->absolute(); $zero = new Money(0, $this->remainingDueAmount->getCurrency()); if ($this->remainingDueAmount->lessThanOrEqual($zero)) { $this->closingDate = new \DateTimeImmutable('now', new \DateTimeZone('UTC')); } $this->payments[] = new CollectedPayment( $payment->getReceptionDate(), $amount, $payment->getSource() // wire, check, cash, etc. ); } }
  16. class Invoice { public function isClosed(): bool { return $this->closingDate

    instanceof \DateTimeImmutable; } public function isPaid(): bool { $zero = new Money(0, $this->remainingDueAmount->getCurrency()); return $this->remainingDueAmount->lessThanOrEqual($zero); } public function isOverpaid(): bool { $zero = new Money(0, $this->remainingDueAmount->getCurrency()); return $this->remainingDueAmount->lessThan($zero); } }
  17. Collecting Payments $invoice->collectPayment(new Payment( new \DateTimeImmutable('2018-03-04'), new Money(4900, new Currency('EUR')),

    new WireTransferPayment('450357035') )); $invoice->collectPayment(new Payment( new \DateTimeImmutable('2018-03-08'), new Money(5100, new Currency('EUR')), new WireTransferPayment('248748484') ));
  18. Value Objects A value object is an object representing an

    atomic value or concept. The value object is responsible for validating the consistency of its own state. It’s designed to always be in a valid, consistent and immutable state.
  19. Value Object Properties •They don’t have an identity •They’re responsible

    for validating their state •They are immutable by design •They are always valid by design •Equality is based on what they represent •They are interchangeable without side effects
  20. final class Currency { private $code; public function __construct(string $code)

    { if (!in_array($code, ['EUR', 'USD', 'CAD'], true)) { throw new \InvalidArgumentException('Unsupported currency.'); } $this->code = $code; } public function equals(self $other): bool { return $this->code === $other->code; } }
  21. final class Money { private $amount; private $currency; public function

    __construct(int $amount, Currency $currency) { $this->amount = $amount; $this->currency = $currency; } // ... }
  22. final class Money { // ... public function add(self $other):

    self { $this->ensureSameCurrency($other->currency); return new self($this->amount + $other->amount, $this->currency); } private function ensureSameCurrency(Currency $other): void { if (!$this->currency->equals($other)) { throw new \RuntimeException('Currency mismatch'); } } }
  23. $a = new Money(100, new Currency('EUR')); // 1€ $b =

    new Money(500, new Currency('EUR')); // 5€ $c = $a->add($b); // 6€ $c->add(new Money(300, new Currency('USD'))); // Error
  24. Design Patterns In software design, a design pattern is an

    abstract generic solution to solve a particular redundant problem. — Wikipedia
  25. Creational Abstract Factory Builder Factory Method Prototype Singleton Creational design

    patterns are responsible for encapsulating the algorithms for producing and assembling objects. Patterns
  26. Structural Adapter Bridge Composite Decorator Facade Flyweight Proxy Structural design

    patterns organize classes in a way to separate their implementations from their interfaces. Patterns
  27. Behavioral Chain of Responsibility Command Interpreter Iterator Mediator Memento Observer

    State Strategy Template Method Visitor Behavioral design patterns organize objects to make them collaborate together while reducing their coupling. Patterns
  28. Singleton The singleton pattern ensures that only one object of

    a particular class is ever created. All further references to objects of the singleton class refer to the same underlying instance. — GoF
  29. Prototype The prototype pattern is used to instantiate a new

    object by copying all of the properties of an existing object, creating an independent clone. This practise is particularly useful when the construction of a new object is inefficient. — GoF
  30. Problems to solve •Avoid using the «new» keyword to create

    an object, especially when construction is complex and heavy. •Leverage object cloning to build and reconfigure new instances of a class.
  31. HttpFoundation The Request object from the HttpFoundation component provides a

    mechanism to duplicate itself using object cloning to produce a new fresh and configured instance.
  32. class Request { // ... public function duplicate(array $query =

    null, array $request = null, ...) { $dup = clone $this; if (null !== $query) { $dup->query = new ParameterBag($query); } if (null !== $request) { $dup->request = new ParameterBag($request); } // ... if (null !== $server) { $dup->server = new ServerBag($server); $dup->headers = new HeaderBag($dup->server->getHeaders()); } $dup->languages = null; $dup->charsets = null; // ... if (!$dup->get('_format') && $this->get('_format')) { $dup->attributes->set('_format', $this->get('_format')); } if (!$dup->getRequestFormat(null)) { $dup->setRequestFormat($this->getRequestFormat(null)); } return $dup; } }
  33. trait ControllerTrait { // ... protected function forward( string $controller,

    array $path = [], array $query = [] ): Response { $request = $this->container->get('request_stack')->getCurrentRequest(); $path['_controller'] = $controller; $subRequest = $request->duplicate($query, null, $path); return $this ->container ->get('http_kernel') ->handle($subRequest, HttpKernelInterface::SUB_REQUEST); } }
  34. Form The FormBuilder object of the Form component uses object

    cloning and the Prototype pattern to build a new configured instance of FormConfig.
  35. class FormConfigBuilder implements FormConfigBuilderInterface { // ... private $locked =

    false; public function getFormConfig() { if ($this->locked) { throw new BadMethodCallException('...'); } // This method should be idempotent, so clone the builder $config = clone $this; $config->locked = true; return $config; } }
  36. class FormBuilder extends FormConfigBuilder { // ... public function getFormConfig()

    { /** @var $config self */ $config = parent::getFormConfig(); $config->children = array(); $config->unresolvedChildren = array(); return $config; } public function getForm() { // ... $form = new Form($this->getFormConfig()); // ... return $form; } }
  37. Benefits • Simple, no need for factories or subclassing •

    Reduce repeating initialization code • Create complex objects faster • Provide an alternative for subclassing for complex object with many configurations Disadvantages • Cloning deep and complex objects graphs composed of many nested objects can be hard
  38. Abstract Factory The abstract factory pattern provides an interface for

    creating families of related or dependent objects without specifying their concrete classes. — Wikipedia
  39. namespace Symfony\Component\Messenger\Adapter\Factory; use Symfony\Component\Messenger\Transport\ReceiverInterface; use Symfony\Component\Messenger\Transport\SenderInterface; interface AdapterFactoryInterface { public

    function createReceiver(string $dsn, array $options): ReceiverInterface; public function createSender(string $dsn, array $options): SenderInterface; public function supports(string $dsn, array $options): bool; }
  40. class AmqpAdapterFactory implements AdapterFactoryInterface { private $encoder; private $decoder; private

    $debug; public function __construct(EncoderInterface $encoder, DecoderInterface $decoder, bool $debug) { $this->encoder = $encoder; $this->decoder = $decoder; $this->debug = $debug; } public function createReceiver(string $dsn, array $options): ReceiverInterface { return new AmqpReceiver($this->decoder, Connection::fromDsn($dsn, $options, $this->debug)); } public function createSender(string $dsn, array $options): SenderInterface { return new AmqpSender($this->encoder, Connection::fromDsn($dsn, $options, $this->debug)); } public function supports(string $dsn, array $options): bool { return 0 === strpos($dsn, 'amqp://'); } }
  41. class ChainAdapterFactory implements AdapterFactoryInterface { /** @var AdapterFactoryInterface[] */ private

    $factories; public function createReceiver(string $dsn, array $options): ReceiverInterface { foreach ($this->factories as $factory) { if ($factory->supports($dsn, $options)) { return $factory->createReceiver($dsn, $options); } } throw new \InvalidArgumentException(sprintf('No adapter supports the given DSN "%s".', $dsn)); } public function createSender(string $dsn, array $options): SenderInterface { foreach ($this->factories as $factory) { if ($factory->supports($dsn, $options)) { return $factory->createSender($dsn, $options); } } throw new \InvalidArgumentException(sprintf('No adapter supports the given DSN "%s".', $dsn)); } }
  42. Benefits • Each factory produces one specific concrete type •

    Easy to replace a concrete factory by another • Adaptability to the run-time environment • Objects construction is centralized Disadvantages • Lots of classes and interfaces are involved • Client code doesn’t know the exact concrete type • Hard to implement
  43. Factory Method Define an interface for creating an object, but

    let subclasses decide which class to instantiate. The Factory method lets a class defer instantiation it uses to subclasses. — GoF
  44. interface CarFactory { public function makeCar(); } interface Car {

    public function getType(); } /* Concrete implementations of the factory and car */ class SedanFactory implements CarFactory { public function makeCar() { return new Sedan(); } } class Sedan implements Car { public function getType() { return 'Sedan'; } } $factory = new SedanFactory(); $car = $factory->makeCar(); print $car->getType();
  45. <?php interface Person { public function GetName(); } class Villager

    implements Person { public function GetName() { return "Village Person"; } } class CityPerson implements Person { public function GetName() { return "City Person"; } }
  46. class Factory { public function GetPerson(PersonType $type): Person { switch

    ($type) { case 'Rural': return new Villager(); case 'Urban': return new CityPerson(); default: throw new NotSupportedException(); } } }
  47. namespace Symfony\Component\Form; interface ResolvedFormTypeFactoryInterface { /** * @param FormTypeInterface $type

    * @param FormTypeExtensionInterface[] $typeExtensions * @param ResolvedFormTypeInterface|null $parent * * @return ResolvedFormTypeInterface */ public function createResolvedType( FormTypeInterface $type, array $typeExtensions, ResolvedFormTypeInterface $parent = null ); }
  48. namespace Symfony\Component\Form; class ResolvedFormTypeFactory implements ResolvedFormTypeFactoryInterface { public function createResolvedType(

    FormTypeInterface $type, array $typeExtensions, ResolvedFormTypeInterface $parent = null ) { return new ResolvedFormType($type, $typeExtensions, $parent); } }
  49. $f = new ResolvedFormTypeFactory(); $form = $f->createResolvedType(new FormType()); $date =

    $f->createResolvedType(new DateType(), [], $form); $bday = $f->createResolvedType(new BirthdayType(), [], $date);
  50. namespace Symfony\Component\Form\Extension\DataCollector\Proxy; use Symfony\Component\Form\Extension\DataCollector\FormDataCollectorInterface; use Symfony\Component\Form\FormTypeInterface; use Symfony\Component\Form\ResolvedFormTypeFactoryInterface; use Symfony\Component\Form\ResolvedFormTypeInterface;

    class ResolvedTypeFactoryDataCollectorProxy implements ResolvedFormTypeFactoryInterface { private $proxiedFactory; private $dataCollector; public function __construct(ResolvedFormTypeFactoryInterface $proxiedFactory, FormDataCollectorInterface $dataCollector) { $this->proxiedFactory = $proxiedFactory; $this->dataCollector = $dataCollector; } public function createResolvedType(FormTypeInterface $type, array $typeExtensions, ResolvedFormTypeInterface $parent = null) { return new ResolvedTypeDataCollectorProxy( $this->proxiedFactory->createResolvedType($type, $typeExtensions, $parent), $this->dataCollector ); } }
  51. $factory = new ResolvedTypeDataCollectorProxyFactory( new ResolvedFormTypeFactory(), new FormDataCollector(…) ); $form

    = $f->createResolvedType(new FormType()); $date = $f->createResolvedType(new DateType(), [], $form); $bday = $f->createResolvedType(new BirthdayType(), [], $date);
  52. class FormRegistry implements FormRegistryInterface { /** * @var ResolvedFormTypeFactoryInterface */

    private $resolvedTypeFactory; private function resolveType(FormTypeInterface $type) { // ... try { // ... return $this->resolvedTypeFactory->createResolvedType( $type, $typeExtensions, $parentType ? $this->getType($parentType) : null ); } finally { unset($this->checkedTypes[$fqcn]); } } }
  53. // Prod environment $factory = new ResolvedFormTypeFactory(); // Dev environment

    $factory = new ResolvedTypeFactoryDataCollectorProxy( new ResolvedFormTypeFactory(), new FormDataCollector(...) ); // Factory injection $registry = new FormRegistry([...], $factory); $type = $registry->getType(EmailType::class);
  54. Benefits • Each factory produces one specific concrete type •

    Easy to replace a concrete factory by another • Adaptability to the run-time environment • Objects construction is centralized Disadvantages • Lots of classes and interfaces are involved • Client code doesn’t know the exact concrete type • Hard to implement
  55. Builder The Builder design pattern separates the construction of a

    complex object from its representation. — Wikipedia
  56. Problems • Avoiding constructors that have too many optional parameters.

    • Simplifying the process of creating a complex object. • Abstract the steps order to assemble a complex object.
  57. Doctrine Doctrine comes with a QueryBuilder object in order to

    provide a simpler way to produce a Query instance from a Repository.
  58. class UserRepository extends EntityRepository { public function byEmailAddress(string $email): ?User

    { $query = $this ->createQueryBuilder('u, p') ->leftJoin('u.profile', 'p') ->where('LOWER(u.emailAddress) = :email') ->andWhere('u.active = :active') ->setParameter('email', mb_strtolower($email)) ->setParameter('active', 1) ->getQuery() ; return $query->getOneOrNullResult(); } }
  59. class QueryBuilder { // ... public function where($predicates) { if

    ( ! (func_num_args() == 1 && $predicates instanceof Expr\Composite)) { $predicates = new Expr\Andx(func_get_args()); } return $this->add('where', $predicates); } public function setMaxResults($maxResults) { $this->_maxResults = $maxResults; return $this; } }
  60. class QueryBuilder { // ... public function getQuery() { $parameters

    = clone $this->parameters; $query = $this->_em->createQuery($this->getDQL()) ->setParameters($parameters) ->setFirstResult($this->_firstResult) ->setMaxResults($this->_maxResults); if ($this->lifetime) { $query->setLifetime($this->lifetime); } if ($this->cacheMode) { $query->setCacheMode($this->cacheMode); } if ($this->cacheable) { $query->setCacheable($this->cacheable); } if ($this->cacheRegion) { $query->setCacheRegion($this->cacheRegion); } return $query; } }
  61. Form The Symfony Form component provides a FormBuilder object, which

    simplifies the construction and the initialization of a Form instance.
  62. class RegistrationType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array

    $options) { $builder ->add('emailAddress', EmailType::class) ->add('firstName', TextType::class) ->add('lastName', TextType::class) ->add('password', RepeatedType::class, [ 'type' => PasswordType::class, ]) ->add('submit', SubmitType::class) ; } public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults([ 'data_class' => Registration::class, ]); } }
  63. interface FormBuilderInterface extends FormConfigBuilderInterface { public function add($child, $type =

    null, array $options = []); public function create($name, $type = null, array $options = []); public function get($name); public function remove($name); public function has($name); public function all(); public function getForm(); }
  64. interface FormConfigBuilderInterface extends FormConfigInterface { public function addEventListener($eventName, $listener, $priority

    = 0); public function addEventSubscriber(EventSubscriberInterface $subscriber); public function addViewTransformer(DataTransformerInterface $viewTransformer, $forcePrepend = false); public function resetViewTransformers(); public function addModelTransformer(DataTransformerInterface $modelTransformer, $forceAppend = false); public function resetModelTransformers(); public function setAttribute($name, $value); public function setAttributes(array $attributes); public function setDataMapper(DataMapperInterface $dataMapper = null); public function setDisabled($disabled); public function setEmptyData($emptyData); public function setErrorBubbling($errorBubbling); public function setRequired($required); public function setPropertyPath($propertyPath); public function setMapped($mapped); public function setByReference($byReference); public function setInheritData($inheritData); public function setCompound($compound); public function setType(ResolvedFormTypeInterface $type); public function setData($data); public function setDataLocked($locked); public function setFormFactory(FormFactoryInterface $formFactory); public function setAction($action); public function setMethod($method); public function setRequestHandler(RequestHandlerInterface $requestHandler); public function setAutoInitialize($initialize); public function getFormConfig(); }
  65. class FormBuilder extends FormConfigBuilder implements \IteratorAggregate, FormBuilderInterface { // ...

    public function getForm() { if ($this->locked) { throw new BadMethodCallException('...'); } $this->resolveChildren(); $form = new Form($this->getFormConfig()); foreach ($this->children as $child) { // Automatic initialization is only supported on root forms $form->add($child->setAutoInitialize(false)->getForm()); } if ($this->getAutoInitialize()) { // Automatically initialize the form if it is configured so $form->initialize(); } return $form; } }
  66. Form The Symfony Form component provides a FormFactoryBuilder object, which

    simplifies the construction and the initialization of a FormFactory instance.
  67. $factory = (new FormFactoryBuilder()) ->addExtension(new CoreExtension(...)) ->addExtension(new CsrfExtension(...)) ->addExtension(new ValidatorExtension(...))

    ->addType(new CustomFormType()) ->addType(new OtherFormType()) ->addTypeExtension(new EmojiRemoverTypeExtension()) ->addTypeGuesser(new CustomTypeGuesser(...)) ->getFormFactory() ;
  68. class FormFactoryBuilder implements FormFactoryBuilderInterface { private $resolvedTypeFactory; private $extensions =

    array(); private $types = array(); private $typeExtensions = array(); private $typeGuessers = array(); // ... public function addExtension(FormExtensionInterface $extension) { $this->extensions[] = $extension; return $this; } public function addType(FormTypeInterface $type) { $this->types[] = $type; return $this; } public function addTypeExtension(FormTypeExtensionInterface $typeExtension) { $this->typeExtensions[$typeExtension->getExtendedType()][] = $typeExtension; return $this; } public function addTypeGuesser(FormTypeGuesserInterface $typeGuesser) { $this->typeGuessers[] = $typeGuesser; return $this; }
  69. class FormFactoryBuilder implements FormFactoryBuilderInterface { // ... public function getFormFactory()

    { $extensions = $this->extensions; if (count($this->types) > 0 || count($this->typeExtensions) > 0 || count($this->typeGuessers) > 0) { if (count($this->typeGuessers) > 1) { $typeGuesser = new FormTypeGuesserChain($this->typeGuessers); } else { $typeGuesser = isset($this->typeGuessers[0]) ? $this->typeGuessers[0] : null; } $extensions[] = new PreloadedExtension($this->types, $this->typeExtensions, $typeGuesser); } return new FormFactory(new FormRegistry( $extensions, $this->resolvedTypeFactory ?: new ResolvedFormTypeFactory() )); } }
  70. Validator The Symfony Validator component provides a ConstraintViolationBuilder object, which

    simplifies the construction of a new ViolationConstraint instance.
  71. class ExecutionContext implements ExecutionContextInterface { private $root; private $translator; private

    $translationDomain; private $violations; private $value; private $propertyPath = ''; private $constraint; // ... public function buildViolation($message, array $parameters = []) { return new ConstraintViolationBuilder( $this->violations, $this->constraint, $message, $parameters, $this->root, $this->propertyPath, $this->value, $this->translator, $this->translationDomain ); } }
  72. class ConstraintViolationBuilder implements ConstraintViolationBuilderInterface { // ... public function atPath($path)

    { $this->propertyPath = PropertyPath::append($this->propertyPath, $path); return $this; } public function setParameter($key, $value) { $this->parameters[$key] = $value; return $this; } public function setInvalidValue($invalidValue) { $this->invalidValue = $invalidValue; return $this; } public function setPlural($number) { $this->plural = $number; return $this; }
  73. class ConstraintViolationBuilder implements ConstraintViolationBuilderInterface { // ... public function addViolation()

    { if (null === $this->plural) { $translatedMessage = $this->translator->trans( $this->message, $this->parameters, $this->translationDomain ); } else { try { $translatedMessage = $this->translator->transChoice( $this->message, $this->plural, $this->parameters, $this->translationDomain ); } catch (\InvalidArgumentException $e) { $translatedMessage = $this->translator->trans( $this->message, $this->parameters, $this->translationDomain ); } } $this->violations->add(new ConstraintViolation( $translatedMessage, $this->message, $this->parameters, $this->root, $this->propertyPath, $this->invalidValue, $this->plural, $this->code, $this->constraint, $this->cause )); }} Translate the error message. Construct the violation object and add it to the list.
  74. class UniqueEntityValidator extends ConstraintValidator { //... public function validate($entity, Constraint

    $constraint) { // ... $value = $this->formatWithIdentifiers($em, $class, $invalidValue); $this->context->buildViolation($constraint->message) ->atPath($errorPath) ->setParameter('{{ value }}', $value) ->setInvalidValue($invalidValue) ->setCode(UniqueEntity::NOT_UNIQUE_ERROR) ->setCause($result) ->addViolation(); } }
  75. Benefits • Avoid constructor with many optional arguments • No

    need to know the exact order of build steps • Leverage fluent interfaces • Ideal for high level of encapsulation & consistency • Different builder implementations can be offered Disadvantages • Duplicated code in builder and builded object classes • Sometimes very verbose
  76. Differences with Abstract Factory • Abstract Factory emphasizes a family

    of product objects (either simple or complex). Builder focuses on constructing a complex object step by step. • Abstract Factory focuses on what is made. Builder focus on how it is made. • Abstract Factory focuses on defining many different types of factories to build many products, and it is not a one builder for just one product. Builder focus on building a one complex but one single product. • Abstract Factory defers the choice of what concrete type of object to make until run time. Builder hides the logic/operation of how to compile that complex object. • In Abstract Factory, every method call creates and returns different objects. In Builder, only the last method call returns the object, while other calls partially build the object https://javarevealed.wordpress.com/2013/08/12/builder-design-pattern/
  77. Singleton The singleton pattern ensures that only one object of

    a particular class is ever created. All further references to objects of the singleton class refer to the same underlying instance. — GoF
  78. Prototype The prototype pattern is used to instantiate a new

    object by copying all of the properties of an existing object, creating an independent clone. This practise is particularly useful when the construction of a new object is inefficient. — GoF
  79. Abstract Factory The abstract factory pattern provides an interface for

    creating families of related or dependent objects without specifying their concrete classes. — Wikipedia
  80. Factory Method Define an interface for creating an object, but

    let subclasses decide which class to instantiate. The Factory method lets a class defer instantiation it uses to subclasses. — GoF
  81. Builder The Builder design pattern separates the construction of a

    complex object from its representation. — Wikipedia