是什么
设计模式是一种解决特定问题的套路,主要遵循SOLID原则,即单一职责原则、接口隔离原则、开放封闭原则、里氏替换原则和依赖倒置原则。
常见的设计模式
-
MVC(Model-View-Controller)模式:将应用程序分为三个部分:模型(Model)、视图(View)和控制器(Controller),以实现分离关注点的目标。
-
MVVM(Model-View-ViewModel)模式:是MVC模式的改进,它通过使用ViewModel来进一步分离模型和视图,使得模型和视图之间的通信更加简单。
-
观察者模式(Observer Pattern):定义了一种一对多的依赖关系,当一个对象状态改变时,它的所有依赖者都会自动通知。
-
单例模式(Singleton Pattern):保证一个类仅有一个实例,并提供一个全局访问点。
-
工厂模式(Factory Pattern):定义一个创建对象的接口,但是让子类决定实例化哪个类。
-
适配器模式(Adapter Pattern):将一个类的接口转换成客户希望的另一个接口。
-
策略模式(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,使用它来创建了两个组件实例 ComponentA 和 ComponentB。最后,我们将这两个组件实例挂载到页面中,使它们可以正常显示。
当我们需要创建新的组件时,只需要在工厂类的 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函数,该函数接受一个计算策略函数作为参数,并根据选择的策略来计算两个数字的结果。我们在该函数内部定义了两个数字a和b,并使用所选的策略来计算它们的结果。我们还将所选策略的名称存储在selectedStrategy中,以便在计算器组件中显示所选策略。
在模板中,我们使用条件渲染来显示所选策略的名称和计算结果。我们还为每个计算策略定义了一个按钮,以便在单击按钮时选择相应的策略并计算结果。
这就是一个基本的Vue3策略模式的例子。使用函数组合和条件渲染,我们可以根据用户的选择来运行不同的计算策略,并将结果呈现给用户。这种策略模式的实现使得组件可以更灵活地进行计算,并在运行时决定使用哪个算法来完成任务。