0

Once in a while I’m stumbling on switch statements during a Code Review session.

I would like to find a more elegant way of this code

....

$istannceOfClass = $repository->loadFoo(); 
switch($istannceOfClass) 
{  
    case $istannceOfClass instanceOf derivedClassAB:
        $istannceOfClass->callA(); 
        $istannceOfClass->callB(); 
        break;
    case $istannceOfClass instanceOf derivedClassCD:
        $istannceOfClass->callC(); 
        $istannceOfClass->callD(); 
        break;
    case $istannceOfClass instanceOf derivedClassEF:
        $istannceOfClass->callE(); 
        $istannceOfClass->callF(); 
        break;
}

I thought about improve the code. could the anonymous class be used? I can not change the hierarchy and subclasses of $istannceOfClass and $istannceOfClass itself.

an attempt: to improve, correct, throw I used anonymouse for convenience. Code that can not be changed

interface baseclass { }

class ab implements baseclass 
{
    public function callA()
    {
        return "<br>class ab Call A";

    } 

    public function callB()
    {
        return "<br>class ab Call B";
    } 
}

class cd implements baseclass 
{
    public function callC()
    {
        return "<br>class cd Call B";

    } 

    public function callD()
    {
        return "<br>class cd Call C";
    } 
}

New code for refactor first common interface with all methods

interface commonABCDEF 
{
    public function callA(); 
    public function callB();
    public function callC(); 
    public function callD();
    public function callE(); 
}

second abstract class for default behaviour

class abstractCommonAbcdef implements commonABCDEF
{    
    //common behavior
    public function callA() { return '<br>default A'; }
    public function callB() { return '<br>default B'; }
    public function callC() { return '<br>default C'; }
    public function callD() { return '<br>default D'; }
    public function callE() { return '<br>default E'; }
    //abstract public function run(); 

}

adapter for case 1 of switch

$abOverride = new class(new ab()) extends abstractCommonAbcdef 
{   
    public function __construct(baseclass $abcde)
    {
        $this->abcde = $abcde;
    }     

    public function callA() 
    {
        return $this->abcde->callA(); 
    }

    public function callB() 
    {
    return $this->abcde->callB(); 
    }

    public function run()
    {

    } 
};

....

final call al method

$rightClass = new class($abOverride)
{
    public function __construct(abstractCommonAbcdef $abcommonABCDEF) 
    {
        $this->abcommonABCDEF = $abcommonABCDEF; 
    }

    public function getBo() {
        return $this->abcommonABCDEF;
    }
};


echo $rightClass->getBo()->callA(); 
echo $rightClass->getBo()->callB(); 
echo $rightClass->getBo()->callC(); 
echo $rightClass->getBo()->callD();
  • 1
    $class is a apparently a reference to an object, not the name of a class. I think it would be good to rename it to $object. – bdsl May 20 '18 at 13:18
  • Can you add an interface implementation to classAB, classCD and classEF or is there a reason you want to avoid editing them? – bdsl May 20 '18 at 13:19
  • You cannot change the classes, it calls for a virtual method though. – Martin Maat May 20 '18 at 13:28
  • @bdsl technical problem, too long to explain... – BruceStackOverFlow May 20 '18 at 13:31
  • If these ABC methods don't take parameters it should be easy to wrap the response from $repository into common interface (repository itself can implement some contract this way) - even with single method. Parameters change everything. Anyway, I wouldn't expect detailed answer here, because while concrete problem might have abstract solution (many implementations that lead to expected outcome), concrete solution to abstract problem does not exist. – shudder May 21 '18 at 12:46
9

You can make a new interface and have all three classes implement it.

Each one will implement the same method but with a different implementation.

The switch statement can then be replaced with a call to that method.

Martin Fowler calls this refactoring Replace Conditional With Polymorphism. In his example he introduces an abstract superclass rather than an interface. It could work either way, but I tend to prefer interfaces.

  • I also thought this solution I like it. other ideas ? – BruceStackOverFlow May 20 '18 at 13:00
  • @ CandiedOrange right! done! – BruceStackOverFlow May 20 '18 at 13:17
  • @BruceStackOverFlow thank you. Now please delete these comments that are no longer meaningful because of the edit. – candied_orange May 20 '18 at 13:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.