单例模式
基本概念
- 属于创建型模式,它提供了一种创建对象的方式。
- 仅涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。
- 这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
类图
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 需要声明
优点
- 在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例。
- 由于单例模式只生成一个实例,所以减少了系统的性能开销,当一个对象的产生需要 比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一 个单例对象,然后用永久驻留内存的方式来解决(在Java EE中采用单例模式时需要注意JVM 垃圾回收机制)。
- 避免对资源的多重占用,例如一个写文件动作,由于只有一个实例存在 内存中,避免对同一个资源文件的同时写操作。
- 单例模式可以在系统设置全局的访问点,优化和共享资源访问,例如可以设计一个单 例类,负责所有数据表的映射处理。
缺点
- 单例模式一般没有接口,扩展很困难,若要扩展,除了修改代码基本上没有第二种途 径可以实现。单例模式为什么不能增加接口呢?因为接口对单例模式是没有任何意义的,它 要求“自行实例化”,并且提供单一实例、接口或抽象类是不可能被实例化的。当然,在特殊 情况下,单例模式可以实现接口、被继承等,需要在系统开发中根据环境判断。
- 单例模式对测试是不利的。在并行开发环境中,如果单例模式没有完成,是不能进行 测试的,没有接口也不能使用mock的方式虚拟一个对象。
- 单例模式与单一职责原则有冲突。一个类应该只实现一个逻辑,而不关心它是否是单例的,是不是要单例取决于环境,单例模式把“要单例”和业务逻辑融合在一个类中。
应用场景
- 要求生成唯一序列号的环境;
- 在整个项目中需要一个共享访问点或共享数据,例如一个Web页面上的计数器,可以 不用把每次刷新都记录到数据库中,使用单例模式保持计数器的值,并确保是线程安全的;
- 创建一个对象需要消耗的资源过多,如要访问IO和数据库等资源;
- 需要定义大量的静态常量和静态方法(如工具类)的环境,可以采用单例模式(当 然,也可以直接声明为static的方式)。
中介者模式
定义
用一个中介对象封装一系列的对象交互,中介者使各对象不需要显式的相互引用,从而使其耦合松散,而且可以独立的改变它们之间的交互
角色
- Mediator(抽象中介者):定义一个接口,该接口用于各同事对象之间进行通信
- ConcreateMediator(具体中介者):是抽象中介者的子类,通过协调各个同事对象来实现协作行为,维持了对各个同事对象的引用
- Colleague(抽象同事类):它定义各个同事类共有的方法,并声明一些抽象方法供子类实现,维持了一个对抽象中介者的引用,其子类可以通过该引用与中介者通信
- ConcreateColleague(具体同事类):它的抽象同事类的子类,每一个同事对象在需要和其他同事对象通信时,先于中介者通信,通过中介者间接完成与其他同事类的通信,在具体同事类中实现了在抽象同事类中声明的抽象方法
类图
代码示例
// 抽象中介者
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('有房子出租')
// 租客 红红 发送消息 想租房
// 中介传递消息
// 房主 房东叔叔 收到消息 想租房
// 房主 房东叔叔 发送消息 有房子出租
// 中介传递消息
// 租客 红红 收到消息 有房子出租
优点
- 简化了对象之间的关系,将系统的各个对象之间的相互关系进行封装,将各个同事类解耦,使系统变为松耦合
- 提高系统的灵活性,使各个同事对象独立并且易于复用
缺点
- 中介者模式中,中介者承担了较多的责任,一旦中介者对象出现问题,整个系统会受到影响
- 新增一个同事类的时候,需要修改抽象中介者类和具体中介者类
应用场景
中介者模式适用于多个对象之间紧密耦合的情况,紧密耦合的标准是:在类图中出现蜘蛛网状结构。这种情况考虑使用中介者模式,将蜘蛛网状转化为星状。下几个是生活和开发中碰到的例子:
- 中国加入 WTO 之前是各个国家相互贸易,结构复杂,现在是各个国家通过 WTO 来互相贸易
- 机场调度系统
- MVC 框架,其中C(控制器)就是 M(模型)和 V(视图)的中介者
中介者模式 vs观察者模式
- 中介者(mediator)强调的是同事(colleague)类之间的交互
- 观察者中的目标类强调的是目标改变后对观察者进行统一的通讯
- 两者非常相同的一点就是:中介者需要持有并且知道所有的同事类;而目标类也必须持有所有的目标类,但是是以目标类的接口引用方式所持有,所以目标类是不知道观察者的,所有的观察者都是一样的
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。