单例模式

基本概念

  • 属于创建型模式,它提供了一种创建对象的方式。
  • 仅涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。
  • 这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

类图

1.png

Singleton类称为单例类,通过使用private的构造函数确保在一个应用中只产生一个实例,并且是自行化实例的(在Singleton中自己使用 new Singleton())

代码示例

// 创建一个Singleton的类
class SingleObject {
    // 使构造函数私有化
    private constructor() {}
    // 获取唯一可用的对象
    private static sing: SingleObject

    static GetInstance(): SingleObject {
        if(this.sing){
            this.sing = new SingleObject()
        }
        return this.sing
    }
    public GetUserInfo():string{
        let str: string="你好啊"
        return str
    } 
} 
const sing1 = SingleObject.GetInstance()
console.log(117,sing1) // Declaration or statement expected 需要声明   

优点

  1. 在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例。
  2. 由于单例模式只生成一个实例,所以减少了系统的性能开销,当一个对象的产生需要 比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一 个单例对象,然后用永久驻留内存的方式来解决(在Java EE中采用单例模式时需要注意JVM 垃圾回收机制)。
  3. 避免对资源的多重占用,例如一个写文件动作,由于只有一个实例存在 内存中,避免对同一个资源文件的同时写操作。
  4. 单例模式可以在系统设置全局的访问点,优化和共享资源访问,例如可以设计一个单 例类,负责所有数据表的映射处理。

缺点

  1. 单例模式一般没有接口,扩展很困难,若要扩展,除了修改代码基本上没有第二种途 径可以实现。单例模式为什么不能增加接口呢?因为接口对单例模式是没有任何意义的,它 要求“自行实例化”,并且提供单一实例、接口或抽象类是不可能被实例化的。当然,在特殊 情况下,单例模式可以实现接口、被继承等,需要在系统开发中根据环境判断。
  2. 单例模式对测试是不利的。在并行开发环境中,如果单例模式没有完成,是不能进行 测试的,没有接口也不能使用mock的方式虚拟一个对象。
  3. 单例模式与单一职责原则有冲突。一个类应该只实现一个逻辑,而不关心它是否是单例的,是不是要单例取决于环境,单例模式把“要单例”和业务逻辑融合在一个类中。

应用场景

  • 要求生成唯一序列号的环境;
  • 在整个项目中需要一个共享访问点或共享数据,例如一个Web页面上的计数器,可以 不用把每次刷新都记录到数据库中,使用单例模式保持计数器的值,并确保是线程安全的;
  • 创建一个对象需要消耗的资源过多,如要访问IO和数据库等资源;
  • 需要定义大量的静态常量和静态方法(如工具类)的环境,可以采用单例模式(当 然,也可以直接声明为static的方式)。

中介者模式

定义

用一个中介对象封装一系列的对象交互,中介者使各对象不需要显式的相互引用,从而使其耦合松散,而且可以独立的改变它们之间的交互

角色

  • Mediator(抽象中介者):定义一个接口,该接口用于各同事对象之间进行通信
  • ConcreateMediator(具体中介者):是抽象中介者的子类,通过协调各个同事对象来实现协作行为,维持了对各个同事对象的引用
  • Colleague(抽象同事类):它定义各个同事类共有的方法,并声明一些抽象方法供子类实现,维持了一个对抽象中介者的引用,其子类可以通过该引用与中介者通信
  • ConcreateColleague(具体同事类):它的抽象同事类的子类,每一个同事对象在需要和其他同事对象通信时,先于中介者通信,通过中介者间接完成与其他同事类的通信,在具体同事类中实现了在抽象同事类中声明的抽象方法

类图

2.png

代码示例

// 抽象中介者
abstract class Media{
    abstract contact(message:string,person:Human): void
}

// 抽象同事类
abstract class Human {
    name: string
    media: Media
    constructor(name: string, media: Media) {
      this.name = name;
      this.media = media;
    }
}

// 具体的同事类
// 房主类
class HouseOwner extends Human {
    contact(message:string){
        console.log(`房主${this.name}发送消息${message}`)
        this.media.contact(message,this)
    }
    getMessage(message:string){
        console.log(`房主${this.name}收到消息${message}`)
    }
}
// 租客类
class Tenant extends Human {
    contact(message: string) {
      console.log(`租客 ${this.name} 发送消息 ${message}`);
      this.media.contact(message, this);
    }
    getMessage(message: string) {
      console.log(`租客 ${this.name} 收到消息 ${message}`);
    }
}

// 具体中介者类
class ConcreateMedia extends Media {
    private tenant: Tenant;
    private houseOwner: HouseOwner;
    setTenant(tenant: Tenant) {
        this.tenant = tenant;
    }
    setHouseOwner(houseOwner: HouseOwner) {
        this.houseOwner = houseOwner;
    }
    // 由中介者来设置同事对象之间的联系关系
    contact(message: string, person: Human) {
        console.log('中介传递消息');
        if (person === this.houseOwner) {
            this.tenant.getMessage(message);
        } else {
            this.houseOwner.getMessage(message);
        }
    }
}

const media = new ConcreateMedia()
const houseOwner = new HouseOwner('房东叔叔',media)
const tenant = new Tenant('红红',media)

media.setHouseOwner(houseOwner)
media.setTenant(tenant)

tenant.contact('想租房')
houseOwner.contact('有房子出租')
// 租客 红红 发送消息 想租房
// 中介传递消息
// 房主 房东叔叔 收到消息 想租房
// 房主 房东叔叔 发送消息 有房子出租
// 中介传递消息
// 租客 红红 收到消息 有房子出租

优点

  1. 简化了对象之间的关系,将系统的各个对象之间的相互关系进行封装,将各个同事类解耦,使系统变为松耦合
  2. 提高系统的灵活性,使各个同事对象独立并且易于复用

缺点

  1. 中介者模式中,中介者承担了较多的责任,一旦中介者对象出现问题,整个系统会受到影响
  2. 新增一个同事类的时候,需要修改抽象中介者类和具体中介者类

应用场景

中介者模式适用于多个对象之间紧密耦合的情况,紧密耦合的标准是:在类图中出现蜘蛛网状结构。这种情况考虑使用中介者模式,将蜘蛛网状转化为星状。下几个是生活和开发中碰到的例子:

  • 中国加入 WTO 之前是各个国家相互贸易,结构复杂,现在是各个国家通过 WTO 来互相贸易
  • 机场调度系统
  • MVC 框架,其中C(控制器)就是 M(模型)和 V(视图)的中介者

中介者模式 vs观察者模式

  • 中介者(mediator)强调的是同事(colleague)类之间的交互
  • 观察者中的目标类强调的是目标改变后对观察者进行统一的通讯
  • 两者非常相同的一点就是:中介者需要持有并且知道所有的同事类;而目标类也必须持有所有的目标类,但是是以目标类的接口引用方式所持有,所以目标类是不知道观察者的,所有的观察者都是一样的

新数学习小组
13 声望3 粉丝

新数学习小组: