Override public method in subclass in a way that r

2020-05-06 12:45发布

问题:

I have a generic Collection class, with a variety of public getter methods.

To get one item from the Collection, you call get(). There are also several methods that return multiple items: getMany(), getRange(), getAll(), find(), findAll(), query(), queryAny(), etc.

Internally, all of these methods that return multiple items have a loop that calls get() repeatedly, as they aggregate the individual items to return.

A simplified example:

public function get($key){
    return $this->collection[$key];
}

public function getMany($keys){

    $many = array();

    foreach ($keys as $key){
        $many[] = $this->get($key);
    }

    return $many;
}

The problem arises when I want to extend Collection in such a way that I don't want the client to be able to access a single item from the Collection. Basically, I want to disallow access to the get() method.

I can't make get() a private or protected function, because it's public in the parent class.

I also can't override get() in such a way that makes it non-functional (i.e. override it with just a return, or throw an Exception), because all the other methods rely on get(), and I want them to remain functional.

I know I could just override all the methods that rely on get() to rely on some new protected method (i.e. getOne()), but that would violate DRY principles.

WHAT I DON'T WANT TO DO:

class DataSet extends Collection{

    public function get(){
        throw new Exception('get() not implemented in DataSet');
    }

    protected function getOne($key){
        return parent::get($key);
    }    

    public function getMany($keys){

        $many = array();

        foreach ($keys as $key){
            $many[] = $this->getOne($key);
        }

        return $many;
     }
}

If I did the above, I'd have to override a half-dozen methods (some of which are quite complex), and they'd only differ from the parent class' method by a few characters.

So ... what other options do I have? Are there different means to the same end ...?

回答1:

What you could do is make a protected method say _get and this can be what all the methods call internally. You can then expose a get method on all the classes that need access and just have it call _get.