常见的设计模式(Vue)

1,311 阅读6分钟

是什么

设计模式是一种解决特定问题的套路,主要遵循SOLID原则,即单一职责原则、接口隔离原则、开放封闭原则、里氏替换原则和依赖倒置原则。

常见的设计模式

  1. MVC(Model-View-Controller)模式:将应用程序分为三个部分:模型(Model)、视图(View)和控制器(Controller),以实现分离关注点的目标。

  2. MVVM(Model-View-ViewModel)模式:是MVC模式的改进,它通过使用ViewModel来进一步分离模型和视图,使得模型和视图之间的通信更加简单。

  3. 观察者模式(Observer Pattern):定义了一种一对多的依赖关系,当一个对象状态改变时,它的所有依赖者都会自动通知。

  4. 单例模式(Singleton Pattern):保证一个类仅有一个实例,并提供一个全局访问点。

  5. 工厂模式(Factory Pattern):定义一个创建对象的接口,但是让子类决定实例化哪个类。

  6. 适配器模式(Adapter Pattern):将一个类的接口转换成客户希望的另一个接口。

  7. 策略模式(Strategy Pattern):定义一系列算法,把它们一个个封装起来,并且使它们可以相互替换。

观察者模式

在 Vue.js 3 中,我们可以使用 watch 函数和 ref 对象来实现观察者模式。以下是一个使用 Vue.js 3 实现观察者模式的例子:

// 创建一个 ref 对象
const count = ref(0);

// 创建一个 watch 函数
watch(count, (newValue, oldValue) => {
  console.log(`count 变化了,新值为 ${newValue},旧值为 ${oldValue}`);
});

// 修改 count 的值
count.value = 1;
count.value = 2;
count.value = 3;

单例模式

确保只有一个实例被创建并在应用程序的各个部分中共享。在Vue3中,可以通过使用provide/inject API来实现此目的。

<template>
    <div>
        <p>Current count: {{ count }}</p >
        <button @click="incrementCount">Increment count</button>
    </div>
</template>

<script>
import { ref, provide } from 'vue';
let instance = null;

export default {
    setup() {

        // 如果实例不存在,则创建一个新实例
        if (!instance) {
            const count = ref(0);
            instance = {
                count,
                incrementCount() {
                    count.value++;
                }
            };

            // 将实例提供给子组件
            provide('singletonInstance', instance);
        }

        // 返回实例
        return instance;
    }
};
</script>

在这个例子中,我们首先定义了一个全局变量instance,该变量在第一次创建该组件实例时将被初始化。我们使用Vue3的setup函数来创建组件实例,并通过provide将实例暴露给子组件。

子组件可以通过inject访问singletonInstance并获取与父组件相同的单例对象。


<template>
    <div>
        <p>Current count from parent: {{ parentInstance.count }}</p >
        <p>Current count from child: {{ childInstance.count }}</p >
    </div>
</template>

<script>
import { inject } from 'vue';

export default {
    setup() {
        // 从父组件中注入实例
        const parentInstance = inject('singletonInstance');
        // 从子组件中注入实例

        const childInstance = inject('singletonInstance');
        
        return {
            parentInstance,
            childInstance
        };
    }
};

</script>

在子组件中,我们可以使用inject函数来获取从父组件提供的单例实例。在此示例中,我们注入了相同的单例实例,并在父组件和子组件中显示当前计数值。

工厂模式

定义一个工厂类,这个类的作用是根据传入的参数,返回一个特定的实例对象。

在 Vue3.js 中,我们可以使用工厂函数来创建组件实例。以下是一个使用 Vue3.js 实现工厂模式的例子:

// 定义一个工厂类
class ComponentFactory {
  // 根据组件名称返回对应的组件实例
  createComponent(name) {
    switch (name) {
      case 'ComponentA':
        return defineComponent({
          name: 'ComponentA',
          template: '<div>Component A</div>'
        });
      case 'ComponentB':
        return defineComponent({
          name: 'ComponentB',
          template: '<div>Component B</div>'
        });
      default:
        throw new Error(`Unknown component: ${name}`);
    }
  }
}

// 创建一个工厂实例
const componentFactory = new ComponentFactory();

// 使用工厂实例创建组件实例
const ComponentA = componentFactory.createComponent('ComponentA');
const ComponentB = componentFactory.createComponent('ComponentB');

// 将组件实例挂载到页面中
createApp({
  components: {
    ComponentA,
    ComponentB
  },
  template: `
    <div>
      <component-a />
      <component-b />
    </div>
  `
}).mount('#app');

在这个例子中,我们定义了一个工厂类 ComponentFactory,它根据传入的组件名称返回对应的组件实例。然后我们创建了一个工厂实例 componentFactory,使用它来创建了两个组件实例 ComponentAComponentB。最后,我们将这两个组件实例挂载到页面中,使它们可以正常显示。

当我们需要创建新的组件时,只需要在工厂类的 createComponent 方法中添加对应的处理逻辑即可,这样可以让代码更加清晰和易于维护。

适配器模式

适配器模式是一种结构型设计模式,它使得不兼容的接口能够一起工作。在Vue3中,我们可以使用组件适配器来实现这种模式。

以下是一个示例Vue3适配器模式组件:

<template>
    <div>
        <h2>{{ adapter.title }}</h2>
        <ul>
            <li v-for="(item, index) in adapter.items" :key="index">{{ item }}</li>
        </ul>
    </div>
</template>

<script>
import { reactive } from 'vue';

export default {
    props: {
        title: {
            type: String,
            required: true
        },
        items: {
            type: Array,
            required: true
        }
    },

    setup(props) {
        // 创建适配器对象
        const adapter = reactive({
            title: '',
            items: []
        });

        // 适配原始数据格式到适配器格式
        adapter.title = props.title;
        adapter.items = props.items.map(item => item.name);

        return {
            adapter
        };
    }
};
</script>

在这个例子中,我们创建了一个组件适配器,并使用Vue3的reactive函数创建了一个响应式适配器对象。我们通过适配器对象来呈现组件的标题和项列表。

setup函数中,我们使用props参数来访问从父组件传递的原始数据,并将其适配到适配器对象的格式。在这种情况下,我们简单地将每个项的名称提取出来,并将其存储在适配器对象的items属性中。

父组件可以将数据以原始格式传递给该组件,而该组件将其适配到适合自己的格式并渲染。这种适配器模式的实现使得组件可以更灵活地与外部数据进行交互。

<template>
    <div>
        <adapter-component :title="title" :items="items" />
    </div>
</template>

<script>
import AdapterComponent from './AdapterComponent.vue';

export default {
    data() {
        return {
            data: [
                { id: 1, name: 'Item 1' },
                { id: 2, name: 'Item 2' },
                { id: 3, name: 'Item 3' }
            ]
        };
    },

    components: {
        AdapterComponent
    },

    computed: {
        title() {
            return 'List of items';
        },

        items() {
            return this.data;
        }
    }
};
</script>

在父组件中,我们可以使用原始数据格式来定义数据,并通过将数据作为props传递给适配器组件来适配数据格式。适配器组件将原始数据适配到适合自己的格式,并呈现标题和项列表。

策略模式

策略模式是一种行为型设计模式,它使得在运行时能够选择不同的算法来完成特定任务。在Vue3中,我们可以使用函数组合和条件渲染来实现策略模式。

<template>
    <div>
        <h2>计算策略:{{ selectedStrategy }}</h2>
        <p>计算结果:{{ calculationResult }}</p >
        <button @click="calculate(add)">加法</button>
        <button @click="calculate(subtract)">减法</button>
        <button @click="calculate(multiply)">乘法</button>
    </div>
</template>

<script>
import { ref } from 'vue';

export default {
    setup() {
        const calculationResult = ref(0);
        const selectedStrategy = ref('');
        
        const add = (a, b) => a + b;
        const subtract = (a, b) => a - b;
        const multiply = (a, b) => a * b;
        
        const calculate = (strategy) => {
            const a = 10;
            const b = 5;
            calculationResult.value = strategy(a, b);
            selectedStrategy.value = strategy.name;
        };

        return {
            calculationResult,
            selectedStrategy,
            calculate,
            add,
            subtract,
            multiply
        };
    }
};
</script>

setup函数中,我们定义了一个calculate函数,该函数接受一个计算策略函数作为参数,并根据选择的策略来计算两个数字的结果。我们在该函数内部定义了两个数字ab,并使用所选的策略来计算它们的结果。我们还将所选策略的名称存储在selectedStrategy中,以便在计算器组件中显示所选策略。

在模板中,我们使用条件渲染来显示所选策略的名称和计算结果。我们还为每个计算策略定义了一个按钮,以便在单击按钮时选择相应的策略并计算结果。

这就是一个基本的Vue3策略模式的例子。使用函数组合和条件渲染,我们可以根据用户的选择来运行不同的计算策略,并将结果呈现给用户。这种策略模式的实现使得组件可以更灵活地进行计算,并在运行时决定使用哪个算法来完成任务。