修改类以封装而不是继承 [英] Modifying a class to encapsulate instead of inherit

查看:70
本文介绍了修改类以封装而不是继承的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用过的代码库具有从 MDB2 继承的databse类..这构成了所使用的MVC框架(定制的事务)的基础,并且这些模型又从db继承.

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.

我的计划是更改db类以封装MDB2而不是从其继承,然后让它通过其singleton功能维护MDB2的单个实例.

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.

但是,MDB2是一个包含许多方法的大型库,而代码库中的许多高级内容取决于能否访问MDB2方法.

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.

是否有一种方法可以封装MDB2类并将其传递给调用而无需修改高层,也不必为MDB2中的每个方法编写包装方法?

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?

推荐答案

由于您尚未提供任何代码,因此这是一个盲目建议,即您可以用很少的代码删除继承,同时又保持完整功能,并确保仅实例化MDB类一次.

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);
    }
}

这基本上将使您的DB类成为MDB的装饰器.第一次实例化时,DB类将创建并存储MDB的静态实例.这将在任何DB实例(包括子类)之间共享.没有理由在这里使用Singleton.

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.

__ call 拦截器将确保您在数据库中调用的任何调用MDB方法的方法的方法都将被捕获并委托给MDB实例.魔术方法会对性能产生严重影响,因此,当您注意到任何性能影响时,请将任何被调用的方法添加到DB类并从那里进行委托.

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.

不用说,这仍然不是最佳解决方案,因为您的数据库实例仍与模型类紧密耦合.如果您能负担得起更多的重构,我建议将当前从数据库继承的所有类改为封装数据库实例(除非它们是ActiveRecords).然后使用Dependency Injection使数据库实例可用.

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.

这篇关于修改类以封装而不是继承的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆