几种简单的设计模式:单例模式、代理模式、观察者模式、工厂模式

时间:2024-10-13 10:48:25

设计模式的学习

2022-1-22

数据结构、算法、设计模式、为编程的内功,语言和工具则为招式。

所谓设计模式,就是编写代码的思想。

模式是在特定环境下人们解决某类重复出现问题的一套成功或有效的解决方案。

【A pattern is a successful or efficient solution to a recurring problem within a context】

设计模式用于在特定的条件下为一些重复出现的软件设计问题提供合理的、有效的解决方案。

设计模式可分为创建型(Creational),结构型(Structural)和行为型(Behavioral)三种,

其中创建型模式主要用于描述如何创建对象,

结构型模式主要用于描述如何实现类或对象的组合,

行为型模式主要用于描述类或对象怎样交互以及怎样分配职责

优点:

设计模式将有助于提高系统的可维护性和可扩展性、

常见的几种设计模式

设计模式的原则

1. 单一职责原则  
    示例:如设计图表库,Chart类的职责过重,它负责初始化和显示所有的图表对象,
         将各种图表对象的初始化代码和显示代码集中在一个类中实现,违反了“单一职责原则”,不利于类的重用和维护;
2. 开闭原则
    示例:设计图表库,当需要增加新类型的图表时,必须修改Chart类的源代码,违反了“开闭原则”。即扩展是开放的,修改是关闭的。
  • 1
  • 2
  • 3
  • 4
  • 5

0.单例模式

定义:确保一个类最多只有一个实例,并提供一个全局访问点

单例模式可以分为两种:预加载和懒加载

实际应用:在设计管理类的时候,会考虑需不需要,设为单例模式。
创建类的时候,在类的内部生成自己的实例,不允许在类的外部去创建多个实例

//这种形式就是 单例模式的预加载,会占用内存
class soundManager{
    //创建唯一实例
    static Instance=new soundManager;  //使用静态 可是用类名调用属性
    private constructor(){   //私有化构造函数  就能确保一个类最多就只能创建一个实例

    }
}
soundManager.Instance
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
// 这种懒加载的单例模式,在需要的时候会被创建。
class soundManager{
    private static instance:soundManager=null;
    private constructor(){};

    public Instace(){
        if(!soundManger.instace){
            soundManger.instance = new soundManger;
        }
        return soundManger.instance;
    };  //把创建实例变为方法
}
soundManager.Instance(); //使用方法去调用单例实例,当没有的时候在创建实例,比第一种预加载省内存空间。
soundManager.Instance(); //该方法不管调用几次,都是同一个实例
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

1.代理模式

定义:代理模式给某一个客户类对象提供一个代理对象,并由代理对象去帮客户类完成一些任务。通俗的来讲代理模式就是我们生活中常见的中介。

为什么有代理模式?

1.中介隔离作用:在某些情况下,一个客户类不想或者不能直接引用一个委托对象,
而代理类对象可以在客户类和委托对象之间起到中介的作用,其特征是代理类和委托类实现相同的接口。
2.开闭原则,增加功能:代理类除了是客户类和委托类的中介之外,我们还可以通过给代理类增加额外的功能来扩展委托类的功能,
这样做我们只需要修改代理类而不需要再修改委托类,符合代码设计的开闭原则下,对功能增加,扩展是开放的,修改时关闭的。

代理模式分为三类:1. 静态代理 2. 动态代理 3. CGLIB代理

// 静态代理

// 代理委托类接口
interface caculator{
    caculate(num1,mum2):number
}
// 代理人1
class NPC1 implements caculator{
    caculate(num1,num2){
        return num1+num2;
    }
}
// 代理人2
class NPC2 implements caculator{
    caculate(num1,num2){
        return num1-num2;
    }
}

// 客户类
class Person{
    // 用属性定义代理
    agency:caculator
    GetNumber(){
        //拿到计算后的结果
        let num =this.agency.caculte(num1,num2);
        console.log(num+'');
    }
}
// 新建客户类实例
let personOne=new Person;
// 设定一个代理类
personOne.agency= new NPC1;
// 使用代理
personOne.GetNumber(3,4);   //7

// 新建客户类2 实例
let personTwo =new Person;
// 如果设定 NPC2  personTwo 找 NPC2 做代理。
personTwo.agency= new NPC2;
personTwo.GetNumber(3,4); // -1

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

2022-1-24

2.观察者模式

为了更好地描述对象之间存在的这种一对多(包括一对一)的联动,观察者模式应运而生,它定义了对象之间一种一对多的依赖关系

观察者模式(Observer Pattern):定义对象之间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。

观察者模式的别名包括发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式

或从属者(Dependents)模式。观察者模式是一种对象行为型模式。

在观察者模式中,发生改变的对象称为观察目标,而被通知的对象称为观察者,一个观察目标可以对应多个观察者,

而且这些观察者之间可以没有任何相互联系,可以根据需要增加和删除观察者,使得系统更易于扩展。

// 观察者  接口  可以实例化多个观察者。
interface Observer {
    changed: (newvalue: string) => {};  //检测名字的变化 
}

// 被观察对象
class Person {
    private _name: string = '';
    //所有观察者
    observers: Array<Observer> = new Array<Observer>();
    setName(value: string) {
        this._name = value;
        //名字发生变化后,遍历观察者数组,给所有的观察者发消息
        for (let i of this.observers) {
            i.changed(this._name)
        }
    }
    get getName() {
        return this._name;
    }
}

class Test implements Observer {
    changed(newvalue:string){
        console.log("changed!" + newvalue);
    }
}

let personOne = new Person;
let test = new Test;
//设置观察对象
personOne.observers.push(test);

//修改名字,测试是否观察了
personOne.getName('Simpson');
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

2022-1-25

3.工厂模式 分别为: 简单工厂模式(小弟) – 工厂方法模式 – 抽象工厂模式(大哥) ===》》(由容到难)

工厂模式是最常用的一类创建型设计模式,通常我们所说的工厂模式是指工厂方法模式。
简单工厂模式是工厂方法模式的“小弟”,此外,工厂方法模式还有一位“大哥”——抽象工厂模式。
这三种工厂模式各具特色,难度也逐个加大,在软件开发中它们都得到了广泛的应用,成为面向对象软件中常用的创建对象的工具。

简单工厂定义

简单工厂模式(Simple Factory Pattern):定义一个工厂类,它可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类。
因为在简单工厂模式中用于创建实例的方法是静态(static)方法,因此简单工厂模式又被称为静态工厂方法(Static Factory Method)模式,
它属于类创建型模式。
  • 1
  • 2
  • 3

方法流程

1.将需要创建的各种不同对象(例如各种不同的Chart对象)的相关代码封装到不同的类中,这些类称为具体产品类,
而将它们公共的代码进行抽象和提取后封装在一个抽象产品类中,每一个具体产品类都是抽象产品类的子类;
2.提供一个工厂类用于创建各种产品,在工厂类中提供一个创建产品的工厂方法,该方法可以根据所传入的参数不同创建不同的具体产品对象;
客户端只需调用工厂类的工厂方法并传入相应的参数即可得到一个产品对象。
  • 1
  • 2
  • 3
  • 4

简单工厂模式的要点在于:

当你需要什么,只需要传入一个正确的参数,就可以获取你所需要的对象,而无须知道其创建细节。

简单工厂模式结构比较简单,其核心是工厂类的设计

在简单工厂模式中,客户端通过工厂类来创建一个产品类的实例,而无须直接使用new关键字来创建对象,它是工厂模式家族中最简单的一员。

在简单工厂模式结构图中包含如下几个角色:

Factory(工厂角色):

工厂角色即工厂类,它是简单工厂模式的核心,负责实现创建所有产品实例的内部逻辑;工厂类可以被外界直接调用,
创建所需的产品对象;在工厂类中提供了静态的工厂方法factoryMethod(),它的返回类型为抽象产品类型Product。
  • 1
  • 2

Product(抽象产品角色):

它是工厂类所创建的所有对象的父类,封装了各种产品对象的公有方法,它的引入将提高系统的灵活性,
使得在工厂类中只需定义一个通用的工厂方法,因为所有创建的具体产品对象都是其子类对象。
  • 1
  • 2

ConcreteProduct(具体产品角色):

它是简单工厂模式的创建目标,所有被创建的对象都充当这个角色的某个具体类的实例。
每一个具体产品角色都继承了抽象产品角色,需要实现在抽象产品中声明的抽象方法。
  • 1
  • 2
工厂模式主要是用来创建对象的。
// 示例:汽车工厂创建汽车。
// 汽车类型
enum carType {
    BMW,
    Audi,
    Benz
}
// 汽车工厂
class Car{
    name:string;
    // 工厂方法
    static Create(cartype:Cartype):Car{
        let car :Car;
        switch(carType){
            case(carType.BMW):car =new BMW;
            break;
            case(carType.Audi):car =new Audi;
            break;
            case(carType.Benz):car =new Benz;
            break;
        }
    }
}
// 三种汽车的类
class BMW entends carType{};
class Audi entends carType{};
class Benz entends carType{};

let bmw= Car.Create(carType.BMW);// 生产一辆宝马汽车

```typescript
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31