这样的代码该怎么优化呢?

问题有三个,在注释里,大佬们有时间帮忙看下吧,20行左右的代码,辛苦了~

// 父类
class Database {
  private readonly config // 连接数据库的配置
  readonly database // 数据库的实例

  constructor(config: Config) {
    this.config = config // 记录下 config
    this.database = app.database() // 连接数据库,并拿到实例
  }

  // 返回指定集合的实例
  public collection(name: string): Collection {
    return new Collection(this.config, name)
  }
}

// 子类
class Collection extends Database {
  readonly _collection // 集合的实例

  // 调用父类方法,创建集合实例
  constructor(config: Config, name: string) {
    super(config)
    // 问题一:执行下面这句,为啥不会递归呢?
    this._collection = this.database.collection(name)
  }

  // 添加 略
  add() {
    
  }

  // 查找 略
  find() {
    
  }
}


// 问题二:在下面的使用中,是不是实例化了2个 database 对象
const database = new Database({ ... })
const user = database.collection('user')
user.find( ... ) 

// 问题三:有什么更好的写法吗
阅读 2.6k
3 个回答

this.database.collection(name) 不会递归,注意 this.databaseapp.database() 而不是自定义的 Database

new Collection(this.config, name) 会实例化一个 Collection,其继承于 Database

建议就是不要继承,因为 DatabaseCollection 不是继承关系,继承会导致每次 database.collection() 都会连接一次数据库,改成 new Database 连接一次,new Collection 直接在已有连接上获取 collection 即可

问题一,会递归,而且每次都会调用父类的构造函数
问题二,你的代码把两个类设计成互相依赖的,很容易就重复调用构造函数
问题三,复用数据库对象的话,单一依赖会比较好,一个类依赖另一个类,集中管理

/**
 * 数据库配置
 */
interface DatabaseConfig {
    addr: string
    port: number
}

/**
 * 数据库对象键值对
 * 
 * 集中保存数据库对象
 */
interface DatabaseInstanceMap {
    [name: string]: Database
}


function configToString(config: DatabaseConfig) {
    return `${config.addr}+${config.port}`
}

/**
 * 数据库对象
 * 
 * 内部保存数据库的配置 
 */
class Database {
    private data: {
        config: DatabaseConfig
    } // 连接数据库的配置

    public get config(): DatabaseConfig {
        return this.data.config
    }

    constructor(config: DatabaseConfig) {
        this.data = { config } // 记录下 config
    }

    public connect() {
        // 连接数据库并保持连接实例的代码
        console.log('[已连接到数据库]', this.config)
    }

    exec() {
        // 使用保持的连接实例,执行查询任务的代码
        console.log('[查询]', this.config)
    }
}

// 全局数据库实例集合
const databaseInstance: DatabaseInstanceMap = {}

/**
 * 数据库连接
 */
class Connection {

    private databaseKey: string

    /**
     * 建立到数据库的连接
     * @param database 数据库对象
     */
    constructor(database: Database) {
        const key = configToString(database.config)
        this.databaseKey = key

        if (databaseInstance[key]) {
            // 数据库对象已连接到数据库,复用已存在的数据库对象
            return
        } else {
            // 连接数据库,并保存数据库对象
            database.connect()
            databaseInstance[key] = database
        }
    }

    // 添加 略
    add() {
        databaseInstance[this.databaseKey].exec()
    }

    // 查找 略
    find() {
        databaseInstance[this.databaseKey].exec()
    }
}


const accountDatabase = new Database({ addr: '192.168.0.55', port: 10086 })
const orderDatabase = new Database({ addr: '192.168.0.28', port: 10086 })

const user = new Connection(accountDatabase)
const order = new Connection(orderDatabase)

order.find()
user.find()

Collection类 不需要连接数据库的功能
所以不应该继承自 Database, 对它而言只需要连接数据库的的实例
Collection类 应当接收一个 连接的实例作为参数

下面是 mongoose 的 Collection类 的代码

/**
 * Abstract Collection constructor
 *
 * This is the base class that drivers inherit from and implement.
 *
 * @param {String} name name of the collection
 * @param {Connection} conn A MongooseConnection instance
 * @param {Object} [opts] optional collection options
 * @api public
 */

function Collection(name, conn, opts) {
  if (opts === void 0) {
    opts = {};
  }

  this.opts = opts;
  this.name = name;
  this.collectionName = name;
  this.conn = conn;
  this.queue = [];
  this.buffer = true;
  this.emitter = new EventEmitter();

  if (STATES.connected === this.conn.readyState) {
    this.onOpen();
  }
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题