JavaScriptの定番デザインパターン解説(詳細例)

WBOY
リリース: 2022-02-08 17:37:28
転載
1684 人が閲覧しました

この記事では、シングルトン パターン、組み合わせパターン、オブザーバー パターンなど、JavaScript のデザイン パターンに関する関連知識を提供します。お役に立てば幸いです。

JavaScriptの定番デザインパターン解説(詳細例)

1 デザイン パターン

コンセプト

デザイン パターンは、特定の問題を解決するために設計された一連の最適なソリューションです。
オブジェクト指向 - オブジェクトにもっと注意を払う - オブジェクトを定義し、各オブジェクトにプロパティとメソッドを追加する最適な方法を見つける
見つかった最良の解決策 - さまざまな問題に対応するための設計パターン

、さまざまな最適なソリューションがあります - デザイン パターン

一般的なデザイン パターン:

  • 単一ケース パターン
  • 複合パターン
  • オブザーバー モード
  • コマンド モード
  • エージェント モード
  • ファクトリー モード
  • 戦略モード
  • アダプター モード
  • 。 。 。

#1.1 シングルトン モード

データベース接続 - 複数の関数でデータベース操作が必要 - データベースの再接続 - 1000 関数、データベースへの接続 1000 回

登録この機能では、登録ごとにデータベースの操作が必要です。同時に 1,000 人が登録しています。

Mysql データベースには接続制限があります。同時にサポートできるのは最大 200 の接続のみです。

データベースに一度接続する、接続を取得する、データベースを複数回操作する、この接続を使用して操作する

操作方法、同じ接続を使用してデータベース ステートメントを複数回実行する - デザイン パターンを設計できます

設計パターン: クラスを定義します。このクラスが新規作成されると、接続が取得されます。今後データベース ステートメントが実行されるたびに、このクラスから接続を取得できます。

シングルトン モード: 1 つのクラスからのみ取得できます。オブジェクト - このクラスが何回操作されても、最終的に取得されるすべての接続オブジェクトは同じオブジェクトです。

クラスによって作成されたすべてのオブジェクトがまったく同じプロパティを持つようにします。と方法。たとえば、クラスをカプセル化し、一般的に使用される操作関数をメソッドとして配置します。将来的には、毎回同じオブジェクトを使用してこれらのメソッドを呼び出すことができます。

通常、クラスによって作成される各オブジェクトは異なります。

class Carousel{
    }var a = new Carousel();var b = new Carousel();console.log(a === b); // false
ログイン後にコピー
シングルトン モードでは、2 つのオブジェクトが同じになります。つまり、クラスには常にインスタンス オブジェクトが 1 つだけあります。

var single = (function(){
    class Carousel{
       
    }
    var res = undefined;
    return function(){
        if(!res){
           res = new Carousel();
        }
        return res;
    }})();var s1 = single();var s2 = single();console.log(s1 === s2); // true
ログイン後にコピー
変数 P をグローバル変数に公開すると、次のような問題が発生します。

クロージャを使用して p を毎回再定義する問題を解決する

シングルトン モードのコア コード:

function Person(){}function fn(Person){
    var p;
    return function(){
        if(!p){
            p = new Person;
        }
        return p;
    }}var f = fn(Person)var p1 = f()var p2 = f()
ログイン後にコピー
シングルトン モードのアプリケーション シナリオは、カプセル化ツール ライブラリにあります。

例: ツール ライブラリのカプセル化とカプセル化

シングルトン モード アプリケーション ツール ライブラリのカプセル化

     工具库中会有很多的方法 - 方法每次的使用 应该是同一个对象使用的,而不是应该每次都有一个新对象在使用工具
ログイン後にコピー
       // var t = new Tool;
        // t.setCookie('username', 'zs', 20);
        const Tool = (function () {
            class Tool {
                constructor() {
                    if (window.getComputedStyle) {
                        this.flag = true;
                    } else {
                        this.flag = false;
                    }
                }
                /获取节点属性                getStyle(ele, attr) {
                    if (this.flag) {
                        return window.getComputedStyle(ele)[attr];
                    } else {
                        return ele.currentStyle[attr];
                    }
                }

                getStyle(ele, attr) {
                     尝试一段代码   不知道会不会报错
                     尝试成功 后面代码没有什么事
                    尝试失败 会报错 被cathch 捕获到  会将错误信息放到err参数里  catch{} 里可以处理这个错误 也可以不处理这个错误对上面的错误代码进行补救  错误不会再浏览器里报错                    try {
                        return window.getComputedStyle(ele)[attr];
                    } catch (err) {
                        return ele.currentStyle[attr];
                    }
                }
                // 设置节点css属性
                setStyle(ele, styleObj) {
                    for (let attr in styleObj) {

                        ele.style[attr] = styleObj[attr];
                    }
                }
                // 设置cookie
                setCookie(key, value, second, path = '/') {
                    let data = new Date();
                    date.setTime(date.getTime() - 8 * 3600 * 1000 + second * 1000);
                    document.cookie = `${key}=${value};expires=${date};path=${path}`;
                }
            }
            var tool;
            return (function () {
                if (!tool) {
                    tool = new Tool();
                }
                return tool;
            })();
        })();
ログイン後にコピー

1.3 結合モード

結合モードは、ランチャーを作成することです。 。複数のクラスをインスタンス化した後、同じ名前のメソッドを使用して起動しますが、このとき複数のクラスをまとめて起動するランチャーを作成できます。

class Carousel{
    init(){
        console.log("轮播图开始运行");
    }}class Tab{
    init(){
        console.log("选项卡开始运行");
    }}class Enlarge{
    init(){
		console.log("放大镜开始运行");
    }}// 这3个类要运行起来需要各自实例化,并调用每个类中的init方法,此时就可以使用组合模式做一个启动器
ログイン後にコピー
複合モード運用スターター:

class Starter{
    constructor(){
		this.arr = []; // 定义一个数组
    }
    add(className){
        this.arr.push(className); // 将这个多个类放进数组
    }
    run(){
        for(var i=0;i<this.arr.length><hr>1.4 パブリッシュおよびサブスクライブ モード<h3></h3>https://blog.csdn.net/weixin_44070254/article/details/117574565 ?spm=1001.2014.3001.5501<p></p>誰かがサブスクライブし、誰かが公開する<p> パブリッシュおよびサブスクライブ モード: オブザーバーが必要であり、オブザーバーが必要です。オブザーバーがオブザーバーのステータスが変更されたことを発見した場合、タスクは<br> オブザーバーを定義します: <br></p>
<pre class="brush:php;toolbar:false">class Observer{
    // 观察者有名字和任务
    constructor(name,task){
        this.name = name        this.task = task    }}// 定义班主任var bzr = new Observer('班主任',function(state){
    console.log("因为"+state+",所以"+this.name+"罚站");})// 定义了一个年级主任var zr = new Observer('年级主任',function(state){
    console.log("因为"+state+",所以"+this.name+"要找班主任");})// 被观察者class Subject{
    // 有自己的状态
    constructor(state){
        this.state = state        // 观察者们
        this.observer = [];
    }
    // 添加被观察者
    add(...arr){
        this.observer = this.observer.concat(arr)
    }
    // 改变状态
    changeSate(state){
        this.state = state        // 触发观察者的任务
        for(let i=0;i<this.observer.length>オブザーバー パターン (パブリッシュ/サブスクライブ パターンとも呼ばれます)。人がある物を常に監視していて、その物が何かの動作をしようとすると、その動作を行う機能に通知することを指します。 <p></p>例: イベント コードが記述された後、このイベントは実際にページ上のユーザーの動作を継続的に監視します。ユーザーがこのイベントをトリガーすると、イベントを処理する関数が呼び出されます。 <p></p>
<pre class="brush:php;toolbar:false">p.addEventListener("click",function(){});
// 这个事件写好以后,就一直在页面中监控用户行为,用户点击这个元素的时候,就调用函数
ログイン後にコピー
オブザーバー パターンは同様の操作です。オブザーバー パターンを記述する目的は、カスタム イベントを非要素データにバインドすることです。

例: abc イベントを obj にバインドする

分析:

イベントを要素にバインドします。バインド メソッド、トリガー条件、バインド解除があります。確かに。

カスタム イベントをオブジェクトにバインドします。このイベントをバインドする方法、トリガーする方法、そしてこのイベントのバインドを解除する方法です。

つまり:

    イベント バインディングを処理するメソッドが必要です。
  • このイベントをトリガーする方法を処理するメソッドが必要です。
  • このイベントのバインドを解除する方法を処理するメソッドが必要です。
要素のイベント、1 つのイベント タイプを複数の処理関数にバインドできます。

オブジェクトのカスタム イベントを使用して、複数の関数を 1 つのイベント タイプにバインドする方法。

つまり:

イベントの種類に応じた処理関数を格納するスペースが必要です。

1.4.1 プロトタイプ:

class watch{
    bind(){
        
    }
    touch(){
        
    }
    unbind(){
        
    }}var w = new watch();
ログイン後にコピー

現時点で、このオブジェクトにイベントと処理関数をバインドする場合は、パラメーターとしてイベントの種類と処理関数が必要なので、呼び出し時に実際の値を渡します。このイベントを再度バインドします 関数 b を定義すると、元の a が上書きされるため、最初に判断する必要があります 対応する配列にデータがない場合は直接配置します ある場合は ## を追加します#
var w = new watch();w.bind("cl",a); // 给w对象绑定cl事件类型,执行a函数w.bind("cl",b); // 给w对象绑定cl事件类型,执行b函数function a(){
    console.log("事件处理函数a");}function b(){
    console.log("事件处理函数b");}
ログイン後にコピー

で w オブジェクトを出力します。結果:

绑定后的存储结果
JavaScriptの定番デザインパターン解説(詳細例)

1.4.3 触发

触发这个事件需要传入触发哪个事件类型

touch(type){
    // 首先要判断,这个事件类型是否绑定,没有绑定不能触发
    if(!this.obj[type]){
        return false;
    }else{
        // 将这个事件的所有绑定的处理函数一起调用
        for(var i=0;i<this.obj><p>测试:</p>
<table>
<thead><tr class="firstRow"><th>触发测试</th></tr></thead>
<tbody>
<tr><td><img src="https://img.php.cn/upload/article/000/000/067/723219bbf42dba49705fd0fe49beab7d-1.png" alt="JavaScriptの定番デザインパターン解説(詳細例)"></td></tr>
<tr><td><br></td></tr>
</tbody>
</table>
<p>这两个处理函数都没有参数,如果要传入参数的时候该怎么处理?</p>
<p>触发事件的时候就要传入实参</p>
<pre class="brush:php;toolbar:false">w.touch("cl","张三",20);
ログイン後にコピー

触发事件的方法就应该处理这些参数

touch(type,...arr){ // 因为参数不定长,所以使用合并运算符
    // 首先要判断,这个事件类型是否绑定,没有绑定不能触发
    if(!this.obj[type]){
        return false;
    }else{
        // 处理参数:模拟系统事件的参数事件对象,将所有参数都集中在一个对象中
        var e = {
            type:type,
            args:arr        }
        // 将这个事件的所有绑定的处理函数一起调用
        for(var i=0;i<this.obj><p>添加一个带参数的处理函数,并触发事件执行:</p>
<pre class="brush:php;toolbar:false">w.bind("cl",c); // 给w对象绑定cl事件类型,执行c函数w.touch("cl","张三",20);function c(e){
    console.log("我是处理函数c,打印:姓名"+e.name+",年龄"+e.age);}
ログイン後にコピー

结果:

带参数的处理函数处理结果
JavaScriptの定番デザインパターン解説(詳細例)

1.4.5 解绑

解绑也需要知道解绑的事件类型和处理函数

unbind(type,handle){
    // 先判断是否绑定了这个事件
    if(!this.obj[type]){
        return false;
    }else{
        // 从数组中将这个处理函数删除
        for(var i=0;i<this.obj><p>解绑测试:</p>
<table>
<thead><tr class="firstRow"><th>解绑测试结果</th></tr></thead>
<tbody>
<tr><td><img src="https://img.php.cn/upload/article/000/000/067/723219bbf42dba49705fd0fe49beab7d-3.png" alt="JavaScriptの定番デザインパターン解説(詳細例)"></td></tr>
<tr><td><br></td></tr>
</tbody>
</table>
<p>如果绑定事件的时候使用的匿名函数,就无法进行解绑了,所以再添加一个解绑事件所有处理函数的方法:</p>
<pre class="brush:php;toolbar:false">clear(type){
    if(!this.obj[type]){
        return false;
    }else{
        // 直接从对象中将这个属性删除
        delete this.obj[type];
    } }
ログイン後にコピー

1.5 观察者模式

观察者模式跟发布订阅模式不一样的地方在于,要有观察者和被观察者。

创建观察者:

// 创建观察者class Observer{
    // 观察者有姓名和技能 - 技能是一个函数
    constructor(name,skill){
        this.name = name;
        this.skill = skill    }}// 创建观察者var bzr = new Observer('班主任',function(state){
    console.log('因为'+state+'叫家长')})var xz = new Observer('校长',function(state){
    console.log('因为'+state+'叫班主任')})console.log(bzr,xz)
ログイン後にコピー

JavaScriptの定番デザインパターン解説(詳細例)

创建被观察者:

// 创建被观察者
    class Subject{
        // 被观察者有状态 和 观察者列表
        constructor(state){
            this.state = state            this.observers = []
        }
        // 添加观察者
        addObserver(observer){
            var index = this.observers.findIndex(v=>v === observer)
            if(index{
                    v.skill(this.state)
                })
            }
        }
        // 删除观察者
        delObserver(observer){
            var index = this.observers.findIndex(v=>v === observer)
            if(index>=0){
                this.observers.splice(index,1)
            }
        }
    }
    // 创建被观察者
    var xm = new Subject('学习')
    // 添加观察者
    xm.addObserver(bzr)
    xm.addObserver(xz)
    xm.addObserver(bzr)
    console.log(xm)
    // 改变状态
    xm.setState('玩游戏')
ログイン後にコピー

JavaScriptの定番デザインパターン解説(詳細例)


1.6 策略模式

一个问题有多种解决方案,且随时还可以有更多的解决方案,就是策略模式。例如:一个商品在售卖的时候,会有多种折扣方式,慢100减10元,满200减30元等…

商品活动:
满100减10
满200减30
满300打8折

策略模式:将折扣放在闭包中保存起来 - 通过闭包对折扣进行增删改查操作

正常的函数表达方式:

function fn(type,price){
    if(type === '100_10'){
       return price -= 10
    }else if(type === '200_30'){
       return price -= 0
    }else{
        return '没有这种折扣'
    }}fn('100_10',160)
ログイン後にコピー

这种方式,在添加折扣或删除折扣的时候总是需要修改原函数。

策略模式代码:

var calcPrice = (function(){
    // 以闭包的形式存储折扣数据
    var sale = {
        '100_10':function(price){
            return price -= 10
        },
        '200_20':function(price){
            return price -= 20
        }
    }
    function calcPrice(type,price){
        // 闭包中使用折扣
        if(type in sale){
            return sale[type](price)
        }else{
            return '没有这个折扣'
        }
    }
    // 折扣函数添加属性 - 添加折扣
    calcPrice.add = function(type,fn){
        if(type in sale){
            console.log('折扣存在')
        }else{
            sale[type] = fn        }
    }
    // 删除折扣
    calcPrice.del = function(type){
        if(type in sale){
            delete sale[type]
        }else{
            console.log('折扣不存在')
        }
    }
    return calcPrice})()var p = calcPrice('100_10',200)calcPrice.add('200_320',function(price){
    return price -= 50})calcPrice.del('200_330')var p = calcPrice('200_320',200)console.log(p)
ログイン後にコピー

相关推荐:javascript学习教程

以上がJavaScriptの定番デザインパターン解説(詳細例)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:csdn.net
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート