Modifying a class to encapsulate instead of inherit

陌路散爱 提交于 2019-12-01 13:30:43

问题


The codebase I've been handed to work with features a databse class that inherits from MDB2. This forms the basis for the MVC framework in use (a custom built affair) and the models in turn inherit from db.

As I'm sure some of you have noticed, this leads to a rather big problem. Every time you instantiate a model, the result is a new database connection being created. This is obviously quite wasteful. It also means that I'm unable to use transactions as intended, because if a transaction starts in one instance of a model, its effects are invisible to the other instances until a commit occurs.

My plan is to change the db class to encapsulate MDB2 instead of inheriting from it, and then have it maintain a single instance of MDB2 via its singleton functionality.

However, MDB2 is a big library with a lot of methods, and a lot of stuff higher up in the code base depends on being able to access MDB2 methods.

Is there a way to encapsulate the MDB2 class and pass calls to it without modifying the higher layers, and without having to write a wrapper method for every method in MDB2?


回答1:


Since you did not provide any code yet, this is a blind suggestion how you could remove the inheritance with very little code, while at the same time, maintaining full functionality and making sure the MDB class is only instantiated once.

class Db
{
    protected static $_mdb;
    public function __construct()
    {
        if(self::_mdb === NULL) {
            self::_mdb = new MDB;
        }
    }
    public function __call($method, $args)
    {
        return call_user_func_array(array(self::_mdb, $method), $args);
    }
}

This will basically make your DB class a decorator for MDB. On first instantiation, the DB class will create and store a static instance of MDB. This will be shared among any instances of DB, including child classes. There is no reason to use a Singleton here.

The __call interceptor will make sure any methods that you called in DB that call methods on MDB method will be caught and delegated to the MDB instance. Magic methods can have a severe performance impact, so when you notice any performance impact, add any called methods to the DB class and delegate from there.

Needless to say, this is still not the best solution, because your DB instance is still tightly coupled to your model classes. If you can afford more refactoring, I'd suggest to make all the classes that currently inherit from DB encapsulate the DB instance instead (unless they are ActiveRecords). Then use Dependency Injection to make the DB instance available.



来源:https://stackoverflow.com/questions/4244437/modifying-a-class-to-encapsulate-instead-of-inherit

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!