React项目中的JS设计模式应用

本文介绍了设计模式的概念和分类,包括创建型、结构型和行为型模式。在JavaScript中,重点讨论了单例模式、观察者模式、代理模式、工厂模式、装饰器模式、外观模式、迭代器模式、发布-订阅模式、中介者模式和组合模式,并提供了具体的React实现示例。这些设计模式在提高代码复用性、降低复杂性和增强可维护性方面发挥着重要作用。
摘要由CSDN通过智能技术生成

1.什么是设计模式

设计模式(Design Pattern)是软件工程中面临的一般问题的解决方案。它不是成熟的代码,而是原则和思路。设计模式在不同的语言和工具中会有不同的实现方式,但核心思想是不变的。设计模式的主要目的是代码复用和减少系统的复杂性。它通常会解决一类问题,而不是一个具体问题。设计模式允许使用户更加相信系统,它使可维护性较高且方便扩展。

设计模式的类型主要分为三类:

1. 创建型模式:这些设计模式提供用于创建对象的某种机制,它们帮助创建对象,同时隐藏创建细节。比如工厂方法模式、抽象工厂模式、构建者模式、原型模式等。

2. 结构型模式:这些设计模式关注类和对象的组合。通过继承和组合,它们形成了更大的结构。比如适配器模式、装饰者模式、代理模式、外观模式、桥接模式等。

3. 行为型模式:这些设计模式特别关注对象之间的通信。它们处理更多的是对象之间的问题,比如观察者模式、迭代器模式、命令模式、备忘录模式、状态模式等。

总之,设计模式是编程和应用设计中常见的最佳实践。掌握设计模式可以增强语言的表达能力,帮助开发人员解决常见问题,设计清晰、健壮、可重用的代码。

2.设计模式及应用

JavaScript 的主要设计模式有以下几种:

  1. 单例模式:保证一个类只有一个实例,并提供一个访问它的全局访问点。
  2. 观察者模式:定义对象之间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并被自动更新。
  3. 代理模式:控制对对象的访问,通常用于延迟加载costly objects。
  4. 工厂模式:通过工厂方法创建对象,而不需要指定对象的具体类型。
  5. 装饰器模式:动态地给一个对象添加一些额外的功能,继承的替代方案。
  6. 外观模式:提供一个统一的接口,用来访问子系统中的一组接口,外观定义了一个高层接口,让子系统更易使用。
  7. 迭代器模式:顺序访问一个聚合对象中的各个元素,而又不需要知道聚合对象的底层表示。
  8. 发布-订阅模式:又称观察者模式,订阅者建立自己感兴趣的事件,一旦发布者发布消息,对应的订阅者就会得到通知。
  9. 中介者模式:通过一个中间人封装一系列对象相互作用,中介者使各对象不必显式地相互调用,从而使其耦合松散。
  10. 组合模式:组合多个对象形成树形结构以表示对象的全部或者部分层次,使用户可以统一对待单个对象和组合对象。

下面详细介绍一下上述10种设计模式

2.1单例模式(Singleton Pattern)

       单例模式的核心思想在于保证一个类只有一个实例,并提供一个访问它的全局访问点。在 React 中,单例模式的应用场景非常多,如 Redux 中的 store 只需要在应用中存在一个实例,而不是每个组件都重新创建一个。以下是一个 React 中实现单例模式的示例:

const MyComponent = (() => {
  let instance; // 保证一个实例

  function init() {
    // 初始化组件
  }

  return () => {
    if (!instance) {
      // 当实例不存在时才进行初始化
      instance = init();
    }
    return instance;
  };
})();

function App() {
  const component = MyComponent();
  return (
    <div>
      {component}
      {component} {/* 两次调用返回的相同组件实例 */}
    </div>
  );
}

2.2 观察者模式(Observer Pattern)

观察者模式是定义对象之间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都会得到通知并被自动更新。在 React 中,组件的生命周期就是一个非常好的例子,当父组件的状态或属性改变时,子组件会自动重新渲染。以下是一个 React 中使用观察者模式实现组件监听属性的示例:

import React, { useState, useEffect } from "react";

function ObserverComponent(props) {
  const [observedProps, setObservedProps] = useState(props.observedProps);

  useEffect(() => {
    function handlePropsChange() {
      setObservedProps(props.observedProps);
    }
    props.observedProps.on("propChange", handlePropsChange); // 监听属性变化
    return () => {
      props.observedProps.removeListener("propChange", handlePropsChange); // 移除监听
    };
  }, [props.observedProps]);

  return (
    <div>
      {/* 显示监听的属性 */}
      {observedProps.prop1}
      {observedProps.prop2}
      {observedProps.prop3}
    </div>
  );
}

class ObservedProps {
  constructor() {
    this.prop1 = 0;
    this.prop2 = "";
    this.prop3 = [];
    this.listeners = {};
  }

  setProp(propName, newValue) {
    this[propName] = newValue;
    this.emit("propChange"); // 触发属性变化事件
  }

  on(eventName, listener) {
    if (!this.listeners[eventName]) {
      this.listeners[eventName] = [];
    }
    this.listeners[eventName].push(listener);
  }

  removeListener(eventName, listenerToRemove) {
    if (!this.listeners[eventName]) {
      return;
    }

    this.listeners[eventName] = this.listeners[eventName].filter(
      (listener) => listener !== listenerToRemove
    );
  }

  emit(eventName) {
    if (!this.listeners[eventName]) {
      return;
    }

    this.listeners[eventName].forEach((listener) => listener());
  }
}

function App() {
  const [observedProps] = useState(new ObservedProps());
  return (
    <div>
      {/* 修改属性 */}
      <button onClick={() => observedProps.setProp("prop1", 1)}>Set Prop 1</button>
      <button onClick={() => observedProps.setProp("prop2", "abc")}>Set Prop 2</button>
      <button onClick={() => observedProps.setProp("prop3", [1, 2, 3])}>Set Prop 3</button>
      {/* 观察属性变化 */}
      <ObserverComponent observedProps={observedProps} />
    </div>
  );
}

 2.3 代理模式(Proxy Pattern)

代理模式的核心思想在于控制对对象的访问,通常用于延迟加载

import React, { useState } from "react";

// 创建被代理的组件
function RealComponent(props) {
  return <div>{props.text}</div>;
}

// 创建代理组件,通过判断某些条件加载被代理组件
function ProxyComponent(props) {
  const [loaded, setLoaded] = useState(false);

  function handleLoadRealComponent() {
    setLoaded(true);
  }

  if (!loaded) {
    return <button onClick={handleLoadRealComponent}>Load Real Component</button>;
  }

  return <RealComponent {...props} />;
}

function App() {
  return <ProxyComponent text="Hello, World!" />;
}

2.4 工厂模式(Factory Pattern)

工厂模式通过工厂方法创建对象,而不需要指定对象的具体类型。在 React 中,常见的是通过工厂方法创建相似的组件,如数据列表中每行的组件可使用工厂方法创建,并通过传入属性区分不同行的数据。

import React from "react";

// 工厂方法
function createTableRowComponent(data) {
  return function TableRowComponent() {
    return (
      <tr>
        <td>{data.name}</td>
        <td>{data.age}</td>
        <td>{data.gender}</td>
      </tr>
    );
  };
}

function App() {
  const tableData = [
    { name: "Tom", age: 20, gender: "Male" },
    { name: "Jerry", age: 21, gender: "Female" },
    { name: "Felix", age: 22, gender: "Male" },
  ];

  // 通过工厂方法创建组件,传入不同的数据
  const TableRowComponents = tableData.map((data) => createTableRowComponent(data));

  return (
    <table>
      <thead>
        <tr>
          <th>Name</th>
          <th>Age</th>
          <th>Gender</th>
        </tr>
      </thead>
      <tbody>
        {/* 渲染组件列表 */}
        {TableRowComponents.map((Component, index) => (
          <Component key={index} />
        ))}
      </tbody>
    </table>
  );
}

2.5装饰器模式(Decorator Pattern)

装饰器模式动态地给一个对象添加一些额外的功能,是继承的替代方案。在 React 中,高阶组件就是一个很好的装饰器模式的例子,通过将一个组件传入另一个组件中作为参数,返回一个新的、添加了额外功能的组件。

import React from "react";

// 定义高阶组件
function withDecoration(Component) {
  return function DecoratedComponent(props) {
    return (
      <div>
        <h1>Decoration Start</h1>
        <Component {...props} />
        <h1>Decoration End</h1>
      </div>
    );
  };
}

// 创建原始组件
function OriginalComponent() {
  return <div>Original Component</div>;
}

// 使用高阶组件装饰原始组件
const DecoratedComponent = withDecoration(OriginalComponent);

function App() {
  return <DecoratedComponent />;
}

2.6 外观模式(Facade Pattern)

外观模式提供一个统一的接口,用来访问子系统中的一组接口,外观定义了一个高层接口,让子系统更易使用。在 React 中,可以使用外观模式来库化组件,将多个相关的组件封装在一起,对外暴露一个统一的接口,让使用者不需要进行复杂的组件选择和配置。

import React from "react";

// 将多个相关的组件封装在一起,对外暴露一个统一的接口
function LibraryComponent(props) {
  return (
    <div>
      <ButtonComponent text={props.buttonText} />
      <InputComponent value={props.inputValue} onChange={props.onInputChange} />
      <ListComponent items={props.listItems} />
    </div>
  );
}

// 下面分别是 ButtonComponent、InputComponent 和 ListComponent 组件的定义和使用

function ButtonComponent(props) {
  return <button>{props.text}</button>;
}

function InputComponent(props) {
  return <input value={props.value} onChange={props.onChange} />;
}

function ListComponent(props) {
  return (
    <ul>
      {props.items.map((item, index) => (
        <li key={index}>{item}</li>
      ))}
    </ul>
  );
}

function App() {
  const listItems = ["item1", "item2", "item3"];
  return (
    <LibraryComponent
      buttonText="Click Me!"
      inputValue=""
      onInputChange={() => {}}
      listItems={listItems}
    />
  );
}

2.7迭代器模式(Iterator Pattern)

迭代器模式通过顺序访问聚合对象中的各个元素,而又不需要知道聚合对象的底层表示。在 React 中,迭代器模式常见的应用场景之一是在列表渲染时进行过滤。

import React, { useState } from "react";

function FilteredListComponent(props) {
  const [filter, setFilter] = useState(""); // 搜索关键字

  function handleFilterInputChange(event) {
    setFilter(event.target.value);
  }

  return (
    <div>
      <input value={filter} onChange={handleFilterInputChange} />
      <ul>
        {/* 列表渲染 */}
        {props.listItems
          .filter((item) => item.includes(filter)) // 过滤
          .map((item, index) => (
            <li key={index}>{item}</li>
          ))}
      </ul>
    </div>
  );
}

function App() {
  const listItems = ["item1", "item2", "item3"];
  return <FilteredListComponent listItems={listItems} />;
}

2.8 发布-订阅模式(Publisher-Subscriber Pattern)

发布-订阅模式(又称观察者模式)订阅者会建立自己感兴趣的事件,一旦发布者发布消息,对应的订阅者就会得到通知。在 React 中,发布-订阅模式的实现基于全局的事件机制。一个组件可以订阅一个事件并在事件被触发时更新自己。

import React, { useState } from "react";

const eventEmitter = {
  listeners: {},
  on(eventName, listener) {
    if (!this.listeners[eventName]) {
      this.listeners[eventName] = [];
    }
    this.listeners[eventName].push(listener);
  },
  removeListener(eventName, listenerToRemove) {
    if (!this.listeners[eventName]) {
      return;
    }

    this.listeners[eventName] = this.listeners[eventName].filter(
      (listener) => listener !== listenerToRemove
    );
  },
  emit(eventName, data) {
    if (!this.listeners[eventName]) {
      return;
    }

    this.listeners[eventName].forEach((listener) => listener(data));
  },
};

function SubscriberComponent(props) {
  const [counter, setCounter] = useState(0);

  // 订阅事件
  eventEmitter.on("counterIncrease", (increment) => {
    setCounter((prevCounter) => prevCounter + increment);
  });

  return <div>Counter: {counter}</div>;
}

function PublisherComponent(props) {
  function handleButtonClick() {
    // 触发事件
    eventEmitter.emit("counterIncrease", props.increment);
  }

  return <button onClick={handleButtonClick}>Increase Counter by {props.increment}</button>;
}

function App() {
  return (
    <div>
      <SubscriberComponent />
      <PublisherComponent increment={1} />
    </div>
  );
}

2.9中介者模式

中介者模式是一种行为型设计模式,其目的是降低组件之间的耦合性,它通过提供中介组件,使得其他组件不需要直接依赖彼此,而是通过中介组件来通信。

在 React 中,中介者模式的一个应用场景是将逻辑和状态抽离出来,减少组件之间的直接关系,从而降低代码的复杂度。在这个场景下,中介组件可以扮演状态管理中心的角色,负责管理组件之间的通信和状态管理。

让我们来看一个具体的例子:

import React, { useState } from "react";

const UserList = ({ users, activeUser, onUserSelect }) => (
  <ul>
    {users.map((user) => (
      <li
        key={user.id}
        onClick={() => onUserSelect(user)}
        style={{
          backgroundColor: user.id === activeUser.id ? "#eee" : "auto",
        }}
      >
        {user.name}
      </li>
    ))}
  </ul>
);

const UserDetails = ({ user }) => (
  <div>
    <h3>{user.name}</h3>
    <p>Email: {user.email}</p>
    <p>Phone: {user.phone}</p>
    <p>Website: {user.website}</p>
  </div>
);

const UserContainer = ({ users }) => {
  const [activeUser, setActiveUser] = useState(users[0]);

  const handleUserSelect = (user) => {
    setActiveUser(user);
  };

  return (
    <div>
      <UserList
        users={users}
        activeUser={activeUser}
        onUserSelect={handleUserSelect}
      />
      <UserDetails user={activeUser} />
    </div>
  );
};

export default UserContainer;

2.10组合模式

组合模式是一种结构型设计模式,通过将对象组合成树形结构,使得单个对象和组合对象可以被同等对待。它是一种将对象组织成树形结构的方法,使得客户端通过统一的方式操作对象和组合对象。

在 React 中,组合模式的一个应用场景是组件的嵌套和组织,使得每个组件可以作为单个组件或组合组件来使用。在这个场景下,组件可以根据需要嵌套其他组件,从而实现组件之间的复合和组织。

让我们来看一个具体的例子:

import React from "react";

const List = ({ items }) => (
  <ul>
    {items.map((item, index) => (
      <li key={index}>{item}</li>
    ))}
  </ul>
);

const Header = ({ text }) => <h3>{text}</h3>;

const Paragraph = ({ text }) => <p>{text}</p>;

const Page = ({ title, header, body }) => (
  <div>
    <Header text={title} />
    {header && <Header text={header} />}
    {body && <Paragraph text={body} />}
  </div>
);

const About = () => (
  <Page
    title="About Us"
    header="Our Vision"
    body="We are a team of passionate developers who believe in building a great product that can change the world."
  />
);

const Home = () => (
  <Page title="Welcome">
    <List items={["Item 1", "Item 2", "Item 3"]} />
  </Page>
);

const App = () => (
  <div>
    <About />
    <Home />
  </div>
);

export default App;

上面的代码中,我们定义了五个组件:

  • List:渲染列表;
  • Header:渲染标题;
  • Paragraph:渲染段落;
  • Page:扮演组合容器的角色,根据 props 决定渲染哪些子组件;
  • About 和 Home:分别是两个示例页面,以 Page 作为容器组件,并嵌套其他组件。

在这个示例中,我们使用 Page 组件作为组合容器,将其他组件进行了组合。在 Home 页面中,我们使用 List 组件作为子组件进行嵌套,在 About 页面中,我们使用 Header 和 Paragraph 组件作为子组件进行组合。

这样的设计有一个很明显的优点,那就是组件的嵌套和组合非常容易,我们可以根据需要组合不同的子组件,从而实现非常灵活的组件组合和组织。同时,也符合开闭原则,容易进行组件的扩展和修改。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值