Is code like this is a bad? :
public class TierType
{
private const TYPE_HARD = 'hard';
private const TYPE_MEDIUM = 'medium';
private const TYPE_SOFT = 'soft';
private const SUPPORTED_TYPES = [
self::TYPE_HARD,
self::TYPE_MEDIUM,
self::TYPE_SOFT
];
private function _construct(private string $type) {
}
public static function fromString(string $tierType): self
{
return match ($tierType) {
self::TYPE_HARD => new self(self::TYPE_HARD),
self::TYPE_MEDIUM => new self(self::TYPE_MEDIUM),
self::TYPE_SOFT => new self(self::TYPE_SOFT),
default => throw new Exception('Unsupported tier type provided'),
};
}
public static function createHard(): self
{
return new self(self::self::TYPE_HARD)
}
public static function createMedium(): self
{
return new self(self::self::TYPE_MEDIUM)
}
public static function createSoft(): self
{
return new self(self::self::TYPE_SOFT)
}
}
In this example we not exposing internals of the object, and not delegating creation of the object to outer world, and it's a way I like to do it, and doing for a while already. But recently I heard that is' wrong and it's breaking a SRP as it's not responsibility of object to create it self, and you need to have a public constructor and initiate object from factory. Like this:
public class TierType
{
public const TYPE_HARD = 'hard';
public const TYPE_MEDIUM = 'medium';
public const TYPE_SOFT = 'soft';
public const TYPE_EXTRA_SOFT = 'extra_soft';
private const SUPPORTED_TYPES = [
self::TYPE_HARD,
self::TYPE_MEDIUM,
self::TYPE_SOFT
];
public function _construct(private string $type) {
if (!in_array($this->type, self:::SUPPORTED_TYPES) {
throw new Exception('Unsupported tier type provided')
}
}
}
public class TierFactory {
public function create(string $type): TierType
{
return match ($type) {
self::TYPE_HARD => new TierType(TierType::TYPE_HARD),
self::TYPE_MEDIUM => new TierType(TierType::TYPE_MEDIUM),
self::TYPE_SOFT => new TierType(TierType::TYPE_SOFT),
default => throw new Exception('Unsupported tier type provided'),
};
}
public static function createHard(): TierType
{
return new TierType(TierType::TYPE_HARD)
}
public static function createMedium(): TierType
{
return new TierType(TierType::TYPE_MEDIUM)
}
public static function createSoft(): TierType
{
return new TierType(TierType::TYPE_SOFT)
}
}
I think it also okay, but in this case it's probably unnecessary to create factory as logic is simple, and we allowing other devs to omit that factory and directly call TierType constuctor or create other types of factories. Hopefully we have a validation in the constructor but what if not?? it's harder to thing about object state and add all validation when you delegating it to many classes. From other hadn I think class should tell it's self how to create it, and provide interface of creation. I agree that factory make sense if logic of creation is complicated and some part of it it's not related to object, for example we need to take data from different sources, combine it somehow and after that pass to the object, in that case it's not object responsibility.
Am I thinking correctly??? Or it's really breaking SRP and it's okay to delegate it to factory???
Single Responsibility should be understood as an abstraction of logical tasks in your system. A class should have the single responsibility to perform one single, specific task. A class that manages its own creation doesn't necessarily violates SRP.
That being said, there is a third option to do this that seems more elegant for your specific example. Create separate classes for each different types, each class extending from a common class:
public class TypeHard extends TierType implements TierTypeInterface {
public function __construct()
{
parent::__construct(parent::TYPE_HARD);
}
}
This way is also easier to use with autowired DI containers.
Related
I have a following structure to use Open Close Principle
class Payment{
//this is not a model class
// according to OC principle this class should not focus on the implementation
private $paymentInterface;
public function __construct(PaymentInterface $paymentInterface)
{
$this->paymentInterface = $paymentInterface;
}
//so store method does not know which implementation it will get
public function store($request,$id)
{
return $this->paymentInterface->store($request,$id);
}
}
Interface
interface PaymentInterface{
public function store($request,$id = null);
}
Payment Service Class containing implementation
class PaymentService implements PaymentInterface{
public function store($request,$id = null){
//payment store logic is here
}
}
Controller
class PaymentsController extends Controller{
protected $payment;
public function __construct()
{
$this->payment = new Payment(new PaymentService);
}
public function storePayment(PaymentRequest $request, $id)
{
try {
$response = $this->payment->store($request,$id);
return redirect()->route($this->route.'.index')->with($response['status'],$response['message']);
} catch (\Exception $e) {
return $this->vendorDashboard($e);
}
}
}
My question is:
Is it correct approach to use Open-Close-Principle ?
Using above code I can tell controller that I can use PaymentService class for the implementation.
$payment = new Payment(new PaymentService);
return $payment->store($request,$id);
If later I want to make a payment in different way e.g. make a payment through invoice then I can create new controller, write new implementation in new class e.g. InvoicePaymentService and tell Payment class to use InvoicePaymentService as implementation
$payment = new Payment(new InvoicePaymentService);
return $payment->store($request,$id);
OR
$payment = new Payment(new PayPalPaymentService);
return $payment->store($request,$id);
OR
$payment = new Payment(new AliPayPaymentService);
return $payment->store($request,$id);
I know I can bind Interface with a class through a service provider but if I want to implement a different payment implementation then I will not be able to change the class, right ?
If I am doing it in wrong way please let me know.
This is what service container stands for. You should use contextual binding
Assuming you have an interface: FooInterface
And you have two concrete implementations: GoodFoo and BadFoo
In order to inject different implementations to controllers (or other classes) you must tell it to laravel.
$this->app->when(GoodController::class)
->needs(FooInterface::class)
->give(function () {
return new GoodFoo();
});
$this->app->when(BadController::class)
->needs(FooInterface::class)
->give(function () {
return new BadFoo();
});
And controllers should be:
class GoodController extends Controller
{
protected $foo;
public function __construct(FooInterface $foo)
{
$this->foo = $foo;
}
}
class BadController extends Controller
{
protected $foo;
public function __construct(FooInterface $foo)
{
$this->foo = $foo;
}
}
Please note that most of the time laravel promotes bad software design principles and it rather hard to practise SOLID principles in laravel.
Im working on a project where we're creating many objects throughout the code base.
For some objects thus we decided to use factories to control the process of creating the objects and all their dependencies. This is an example of what we are trying to do:
class CreateBranchFactory implements CreateBranchInterface {
private $branch;
public function __construct() {
$this->branch = new Branch();
$this->branch->scenario = 'create';
}
public function createBranch($branchForm) {
$this->branch->attributes = $branchForm->attributes;
//Example of all the things that I need to do after creating my object
$this->setOfficialNameAndPrinterName($branchForm->official_name, $branchForm->printer_name, $branchForm->name);
$this->createDependencies1();
$this->someOtherFunction();
return $this->branch;
}
public function setOfficialNameAndPrinterName($offName, $printerName, $branchName) {
$this->branch->official_name = $offName ?? $branchName;
$this->branch->printer_name = $printerName ?? $branchName;
$this->branch->save();
}
public function createDependencies1() {
}
And to have a proper contract I created an interface for this. This interface specifies the functions that should be defined
interface CreateBranchInterface {
public function setOfficialNameAndPrinterName(String $offName, String $printerName, String $branchName);
public function createDependencies1();
}
My problem though, is that the contract is specifying all the functions that should be defined, but isnt controlling which functions should get called. Is there any design pattern that I can use, that makes sure that those functions get called??
You can't create such contract by using interfaces - interfaces specifies which methods and how you can call. Calling all these methods is part of implementation, which cannot be provided by interface. You need to create abstract class with implementation and use final keyword to disallow overriding it:
abstract class CreateBranch {
abstract protected function getBranch(): Branch;
final public function createBranch($branchForm) {
$this->getBranch()->attributes = $branchForm->attributes;
//Example of all the things that I need to do after creating my object
$this->setOfficialNameAndPrinterName($branchForm->official_name, $branchForm->printer_name, $branchForm->name);
$this->createDependencies1();
$this->someOtherFunction();
return $this->getBranch();
}
abstract public function setOfficialNameAndPrinterName(String $offName, String $printerName, String $branchName);
abstract public function createDependencies1();
abstract public function someOtherFunction();
}
Unfortunately I'm stuck here.
Consider the following rudimentary examples:
interface ChargeInterface
{
public function charge($amount);
}
class BraintreeCharge implements ChargeInterface
{
public function charge($amount)
{
// braintree logic here
}
}
class StripeCharge implements ChargeInterface
{
public function charge($amount)
{
// stripe logic here
}
}
So there's an interface for charging a payment method, and there are, in this example, two concrete classes which implement the interface.
I'd like to be able to decide on runtime which implementation should be used. So I thought I'd achieve this with custom factory classes:
class PaymentFactory
{
public static $implementation;
public static function charge()
{
return $implementation::charge();
}
}
class StripeFactory
{
public static function charge()
{
return new StripeCharge();
}
}
class BraintreeFactory
{
public static function charge()
{
return new BraintreeCharge();
}
}
Than I could just use the factories:
PaymentFactory::$implemention = StripeFactory::class;
$payments = PaymentFactory::charge();
$payments->charge(100);
Another idea was to use a singleton based logic:
class PaymentFactory extends Singleton
{
protected $implementation;
// Singleton logic missing in this example
public function useImplementation($class)
{
$this->implementation = $class;
}
public function getImplementation()
{
return $this->implementation;
}
public static function charge()
{
$instance = self::getInstance();
return new $instance->getImplementation();
}
}
Later ...
PaymentFactory::getInstance()->useImplementation(StripeCharge::class);
$payments = PaymentFactory::charge();
$payments->charge(100);
Do you've any suggestions regarding best practices here?
I think I'd favour the first one, since the real implementation consists of more than just one class per package, as outlined in the example.
Also it seems to me, this would be the more cleaner way.
There are many topics about this already, but I have not a clear picture of why factory patterns are better practice than Singleton.
An example
class MySingleton {
public static function numberByWhat( $number ) {
return $number + 100;
}
public static function someCharacters( $string ) {
return $string + 'abc';
}
}
class MyOtherSingleton {
public static function getImage( $url ) {
return '<img src="' . $url . MySingleton::numberByWhat( $50 ) . '">';
}
public static function getTextById( $id ) {
if( $id == 3 ) {
return 'this is my text' . MySingleton::someCharacters( 'Yeah' );
}
}
}
function run() {
echo MyOtherSingleton::getImage( 'http://www.example.com/image.png' );
echo MyOtherSingleton::getTextById( 3 );
}
run();
So there we have 2 classes and a function. When I run() I start a function in the second class. Inside the functions in the second class there are calls to the first class.
How would this look like as a factory pattern?
Why is it better as a factory pattern?
So the examples you've given are neither Singletons nor Factories. What you have here are simply "static classes"--classes with only static methods and properties. Factories and Singletons don't really solve the same problem, either, so it's difficult to compare and contrast them.
Singletons
A Singleton is used to manage shared state or avoid the overhead of instantiating a class multiple times when you only really need "one of something".
Here's an example of a Singleton:
class DatabaseConnection {
// Static reference to the single instance of this class we maintain.
protected static $instance;
// Normal instance properties.
protected $mysql;
// Protected constructor to prevent "new DatabaseConnection();"
protected function __construct() {
$this->mysql = new MySQLConnection("localhost", 3306, "appdb");
}
public static function getInstance() {
if (!self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
public function query($sql) {
return $this->mysql->query($sql);
}
}
Whenever you want to use the DatabaseConnection() in your code, you do it like this:
function getUser($userId) {
$userData = DatabaseConnection::getInstance()->query("SELECT * FROM ...");
}
The DatabaseConnection() is only instantiated once, starting the first time it is used. There will never be more than one created.
Dependency Injection / Inversion of Control
The competing strategy to using a Singleton is, basically, Dependency Injection or Inversion of Control. With Dependency Injection, instead of having one shared, staticly-stored instance of a class, the instance is simply passed from class to class and function to function. Here's a simple example:
class DatabaseConnection {
// Normal instance properties.
protected $mysql;
public function __construct() {
$this->mysql = new MySQLConnection("localhost", 3306, "appdb");
}
public function query($sql) {
return $this->mysql->query($sql);
}
}
class UserManager {
protected $databaseConnection;
public function __construct(DatabaseConnection $databaseConnection) {
$this->databaseConnection = $databaseConnection;
}
public function lookupUser($userId) {
return $this->databaseConnection->query("SELECT ...");
}
}
One advantage of Dependency Injection is that you can test your code much more easily. You could, for example, extend DatabaseConnection and call it TestDatabaseConnection, and make it not actually use a real MySQL database, which can make your tests faster and more reliable. So, the debate is really between Singletons and Dependency Injection / Inversion of Control, not Factories.
Factories
So, now, Factories: Factories simplify the creation of objects, return objects of different classes/subclasses, and help to create objects from "templates". As an example, let's say we have different classes to represent different types of users:
class User {
// ...
}
class ModeratorUser extends User {
// ...
}
class AdminUser extends ModeratorUser {
// ...
}
class GuestUser extends User {
// ...
}
Each of these classes contain methods and properties that would be useful for working with a certain type of user account. So, how would you create and return one of these user objects by User ID, ensuring that the correct type of user is returned? We can use a factory pattern:
class UserFactory {
public static function fromUserId(DatabaseConnection $db, $userId) {
$record = $db->query("SELECT * FROM users WHERE user_id ...");
// ...
switch ($record['type']) {
case 'admin':
return new AdminUser($userId);
break;
case 'moderator':
return new ModeratorUser($userId);
break;
case 'guest':
return new GuestUser($userId);
break;
default:
case 'normal':
return new User($userId);
break;
}
}
}
Then, to load the proper User class, you'd just call:
$user = UserFactory::fromUserId($userId);
If it's an admin account, it will be an AdminUser; if it's a guest account, it will be a GuestUser.
class SomeObject {
protected $foo,
$bar;
protected $context;
public function __construct($context) {
$this->context = $context;
}
public function setFoo($val) {
if ($this->context == 'public') {
throw new \Exception('It is impossible to modify foo property in public context!');
}
$this->foo = $val;
}
public function setBar($val) {
if ($this->context == 'api') {
throw new \Exception('It is impossible to modify bar property in API context!');
}
$this->bar = $val;
}
}
As you can see from this piece of "code" - object restricts setters depending on context value. This code is really hard to maintain. How can we rewrite it to make it beautiful and easy maintainable?
My thoughts are:
Make $context an object(s) implementing interface
isAllowed($object, $propertyName).
After making $context an object we have to thing about how can we store "restrictions" in $context object taking in mind there are a lot of different objects similar to SomeObject.
In every setter I should check $this->context->isAllowed($this, 'foo') - it looks not good. So, probably we want to add some "proxy" over SomeObject?
Passing $context to constructor also seems rather ugly for me.
What's your ideas about it?
Just two general observations:
You may want to segregate your classes into two parts: an immutable base class and a mutable extension:
class Foo {
protected $bar, $baz;
}
class MutableFoo extends Foo {
public function setBar($bar) {
$this->bar = $bar;
}
..
}
This easily solves the problem when the context is defined at object instantiation time and won't ever change. Instead of instantiating with a different context which determines the mutability, you simply instantiate a mutable or immutable version of the class.
If you still need more runtime checks, maybe simply using assertions is the best way to simplify the code:
public function setBar($bar) {
$this->assertCanSet('bar');
$this->bar = $bar;
}
protected function assertCanSet($property) {
if (!/* can set $property */) {
throw new Exception("Cannot set property $property");
}
}
Maybe on the construct, fill a list of restricted methods.
so, for instance :
class SomeObject {
protected $foo,
$bar;
protected $context;
protected $restrictedMethods;
public function __construct($context) {
$this->context = $context;
if($this->context == 'public') {
$this->restrictedMethods['setFoo'] = true;
} else if ($this->context == 'api') {
$this->restrictedMethods['setBar'] = true;
}
}
public function setFoo($val) {
if ($this->isRestricted('setFoo')) {
throw new \Exception('It is impossible to modify foo property in '.$this->context.' context!');
}
$this->foo = $val;
}
public function setBar($val) {
if ($this->isRestricted('setFoo')) {
throw new \Exception('It is impossible to modify bar property in '.$this->context.' context!');
}
$this->bar = $val;
}
protected function isRestricted($methodName) {
return array_key_exists($methodName, $this->restrictedMethods);
}
}
If you are trying to write good OOP, then "Interface Segregation" from the SOLID principle may be useful to you.
interface IBase
{
public function doMethod1();
public function doMethod2();
public function doMethod3();
}
interface IFoo extends IBase
{
public function setFoo($val);
}
interface IBar extends IBase
{
public function setBar($val);
}
function doWork(IBase $obj, $val)
{
$obj->doMethod1();
$obj->doMethod2();
$obj->doMethod3();
if ($obj instanceof IFoo) {
$obj->setFoo($val);
}
if ($obj instanceof IBar) {
$obj->setBar($val);
}
}
I doubt this example is exactly what you need, but I will use it to explain the basic idea.
A class should only have a "Single Responsibility". What that responsibility encompasses can vary however, so in general it is best to limit a class's functionality to a single area of concern as best you can.
If you want to follow "Liskov substitution", then throwing exceptions like that in your functions simply because the "context" was irrelevant, violates this principle.
Enter "Interface segregation":
By implementing an interface, you are (to a certain extent) guaranteeing to the caller of the implemented methods, that those methods will work. By excluding them, you are telling the caller that those methods don't exist.
In the example, the doWork function expects an instance of IBase, and safely calls the methods of that interface. After that, it runs introspection of the object to determine if other "applicable" methods are available.
The goal behind interface segregation is to limit the amount of unneeded features a class is forced to implement, so for you, if the context is public, it shouldn't need the setFoo method.
A clean solution would be to have an ObjectFactory class that creates different objects based on a $context parameter, and having two separate classes (with a common base class) that allows writing to the appropriate properties.
Please find below a possible implementation for your schema:
/**
* Base class that allows subclasses to define which properties are
* writable via setters. Subclasses must not add public setters,
* otherwise the mechanism within this class will not work; subclasses
* can add protected setters, though
*/
class PropertyRestricter {
// only properties listed here are writable
// to be initialised by subclasses
protected $writableProperties;
public function __construct() {
// default implementation allows no writable properties
$this->writableProperties = array();
}
public function __call($method, $arguments) {
$matches = false;
// check if a setter was called, extract the property name
// there needs to be at least one argument to the setter
if(count($arguments) && preg_match('/^set([A-Z][a-zA-Z0-9_]+)$/',$matches)) {
$propName = $matches[1];
$propName[0] = strtolower($propName[0]);
// update the property with the given value
// or throw an exception if the property is not writable
if(is_array($this->writableProperties) && in_array($propName, $this->writableProperties)) {
$this->{$propName} = $arguments[0];
} else {
throw new Exception(get_class() . ": $propName is not writable");
}
} else {
// not a setter, nor a public method
// maybe display a user error
}
}
}
/**
* Common properties for the actual classes
*/
class BaseObject extends PropertyRestricter {
protected $foo, $bar;
}
class PublicObject extends BaseObject {
public function __construct() {
parent::__construct();
$this->writableProperties = array('foo');
}
}
class APIObject extends BaseObject {
public function __construct() {
parent::__construct();
$this->writableProperties = array('bar');
}
}
class ObjectFactory {
public function createObject($context) {
switch($context) {
case 'public': return new PublicObject();
case 'api': return new APIObject();
default: return null;
}
}
}
The root of the objects is the PropertyRestricter class that allows subclasses to define which properties are writable. It makes use of the magic method __call() in order to be able to intercept setter calls and to validate the attempt to write to the property. However please note that this works only if subclasses don't add public setters for their properties.
The next level is the BaseObject class, which only defines the two properties, in order to reduce code redundancy.
The last level contains the two classes that get instantiated by the ObjectFactory: PublicObject, 'APIObject. These classes simply initialise thewritablePropertiesarray, as the rest of the work is done by thePropertyRestricter` class.
This is also a scalable solution, as it allows adding as many properties and subclasses as needed, each subclass defining its property writing rules.
Also the property update within the __call() method can be customised, I implemented it in the simplest way by directly setting the property. Actual setters can be used in subclasses and __call() can be updated to call the setters, with the mention that the setters need to be protected in order for the mechanism to work.