python设计模式之工厂模式、策略模式、生产者-消费者模式

前言

这篇主要总结下 设计模式: 工厂模式、策略模式、生产者-消费者模式, 用python举例说明

一、策略模式

1.1 理论理解

顾名思义,根据情况来选择不一样的《策略》。

这种设计模式主要适用于: 希望能够根据特定条件选择方法的情况。 想根据具体场景理解可以看:https://cloud.tencent.com/developer/article/1774687 , 简而言之,根据不同的算法选择,来调用对应的方法,为了更加可维护且运行时动态切换方法等,采用这种模式

1.2 举例

如何根据不同的排序算法来对列表进行排序。

首先,定义一个抽象策略类 SortStrategy,其中包含一个抽象方法 sort,用于定义具体的排序算法。

from abc import ABC, abstractmethod

class SortStrategy(ABC):
    @abstractmethod
    def sort(self, data):
        pass

通过继承SortStrategy, 创建具体的排序策略类 BubbleSort 和 QuickSort,它们分别实现了抽象方法sort。

class BubbleSort(SortStrategy):
    def sort(self, data):
        # 使用冒泡排序算法对数据进行排序
        pass

class QuickSort(SortStrategy):
    def sort(self, data):
        # 使用快速排序算法对数据进行排序
        pass

定义一个上下文类 SorterContext,它负责调用具体的排序策略

class SorterContext:
    def __init__(self, strategy):
        self.strategy = strategy

    def sort_data(self, data):
        self.strategy.sort(data)

最终应用

if __name__ == '__main__':
    data = [15, 2, 8, 1, 9]

    bubble_sort_strategy = BubbleSort()
    sorter1 = SorterContext(bubble_sort_strategy)
    sorter1.sort_data(data)

    print(f"Bubble Sort: {data}")

    quick_sort_strategy = QuickSort()
    sorter2 = SorterContext(quick_sort_strategy)
    sorter2.sort_data(data)

    print(f"Quick Sort: {data}")

二、工厂模式

主要分为三类

  • 简单工厂模式

  • 工厂方法模式

  • 抽象工厂模式

2.1 简单工厂模式

class Animal:
    def __init__(self, name):
        self.name = name

    def speak(self):
        pass

class Dog(Animal):
    def speak(self):
        return "wang!"

class Cat(Animal):
    def speak(self):
        return "miao!"

class AnimalFactory:
    @staticmethod
    def create_animal(animal_type):
        if animal_type == 'Dog':
            return Dog('Dog')
        elif animal_type == 'Cat':
            return Cat('Cat')
        else:
            raise ValueError('Invalid animal type')

animal = AnimalFactory.create_animal('Dog')
print(animal.speak())

AnimalFactory 是一个简单工厂类,通过静态方法 create_animal 来创建不同类型的动物。

通过传入不同的 animal_type 参数,可以创建不同的动物对象。

所以简单工厂模式主要是实现 统一接口,通过type去决定实例化哪个类。

优缺点

  • 优点:

  1. 将对象的创建逻辑封装在工厂类中,对类的使用只需要与工厂类进行交互,统一了对外的接口。

  2. 简单高效

  • 缺点:

  1. 违反了开闭原则(对扩展开放,对修改关闭),当扩展添加新的产品类型时,需要修改工厂类的代码,不符合这个原则,比如想新增一个动物,得改变create_animal中对应的逻辑

  2. 工厂类集中了创建产品的逻辑,当产品较多时,工厂类会变得庞大,代码可读性和可维护性下降。

总结:简单工厂模式适用于需要创建的产品类型较少且不经常变化的情况下,比如业务里已经明确的类型,它能够封装对象的创建过程,提供了一种简单的创建对象的方式。但是当产品类型较多或需要频繁添加新产品时,简单工厂模式的缺点就会显现出来,不利于扩展和维护。在这种情况下,可以考虑使用工厂方法模式或抽象工厂模式来解决这些问题。

2.2 工厂方法模式

from abc import ABC, abstractmethod


class Animal(ABC):
    @abstractmethod
    def speak(self):
        pass


class Dog(Animal):
    def speak(self):
        return "wang!"


class Cat(Animal):
    def speak(self):
        return "miao!"


# 抽象工厂类:每种动物都有自己对于的creator工厂
class AnimalCreator(ABC):
    @abstractmethod
    def create_animal(self):
        pass


class DogCreator(AnimalCreator):
    def create_animal(self):
        return Dog()


class CatCreator(AnimalCreator):
    def create_animal(self):
        return Cat()


dog_creator = DogCreator()
dog = dog_creator.create_animal()
print(dog.speak())


cat_creator = CatCreator()
cat = cat_creator.create_animal()
print(cat.speak())

在这个例子中,AnimalCreator 是一个抽象创建者类,其中定义了一个抽象的工厂方法 create_animal。具体的创建者类 DogCreator 和 CatCreator 分别实现了工厂方法,用于创建不同类型的动物对象。

优缺点

  • 优点:

  1. 符合开闭原则,当需要添加新的类型时,只需要添加新的具体创建者类,不需要修改抽象创建者类或客户端代码。

  2. 每个具体创建者类只负责创建一种产品类型的对象,使得代码更加清晰和易于扩展。

  • 缺点:

  1. 当产品类型较多时,创建者类的数量会增加,增加了代码的复杂性。

  2. 调用方会稍微复杂一些,因为还要了解下创建者类

总结:工厂方法模式适用于子类很多且需要频繁添加新产品的情况以及对于添加的新产品是未知的情况下,它将对象的创建延迟到具体创建者类中,每个具体创建者类负责创建一种产品类型的对象,符合开闭原则,方便了产品的扩展。但是它也增加了类的数量和客户端代码的复杂性,需要权衡使用。

2.2 工厂方法模式

抽象工厂模式是工厂方法模式的升级版本,在有多个分类时,通过抽象工厂模式产生需要的对象是一种非常好的解决方式。

from abc import ABC, abstractmethod


class Button(ABC):
    @abstractmethod
    def render(self):
        pass


class MacOSButton(Button):
    def render(self):
        return 'Render MacOS Button'


class WindowsButton(Button):
    def render(self):
        return 'Render Windows Button'


class Checkbox(ABC):
    @abstractmethod
    def render(self):
        pass


class MacOSCheckbox(Checkbox):
    def render(self):
        return 'Render MacOS Checkbox'


class WindowsCheckbox(Checkbox):
    def render(self):
        return 'Render Windows Checkbox'


class GUIFactory(ABC):
    @abstractmethod
    def create_button(self):
        pass

    @abstractmethod
    def create_checkbox(self):
        pass


class MacOSFactory(GUIFactory):
    def create_button(self):
        return MacOSButton()

    def create_checkbox(self):
        return MacOSCheckbox()


class WindowsFactory(GUIFactory):
    def create_button(self):
        return WindowsButton()

    def create_checkbox(self):
        return WindowsCheckbox()


macos_factory = MacOSFactory()
button = macos_factory.create_button()
checkbox = macos_factory.create_checkbox()
print(button.render())
print(checkbox.render())

windows_factory = WindowsFactory()
button = windows_factory.create_button()
checkbox = windows_factory.create_checkbox()
print(button.render())
print(checkbox.render())

GUIFactory 是一个抽象工厂类,其中定义了创建按钮(Button)和复选框(Checkbox)的抽象方法 create_button 和 create_checkbox。具体工厂类 MacOSFactory 和 WindowsFactory 分别实现了这些抽象方法,用于创建不同平台下的按钮和复选框对象。

优缺点

  • 优点

  1. 将一组相关的产品对象的创建逻辑封装在一个工厂类中,使得调用方与具体产品的创建逻辑解耦,调用方只需要与抽象工厂类进行交互

  • 缺点

  1. 当需要添加新的产品类型时,需要修改抽象工厂类和所有具体工厂类的代码,不符合开闭原则。

  2. 随着产品系列的增加,会比较大的增加代码的复杂性。

总结:相比工厂方法模式只有1种create,当你要新增一类产品的时候,得重新创建工厂接口类。 而抽象工厂中,直接工厂接口类上新增方法,后面的子类同一实现即可,但有个前提条件是这些子类是一个group,有一定的相关和组别性质。

三、生产者-消费者模式

import threading
import time
import random
from queue import Queue

# 创建一个队列作为共享的缓冲区
buffer = Queue(maxsize=10)

# 定义生产者类
class Producer(threading.Thread):
    def run(self):
        while True:
            # 缓冲区已满,等待
            if buffer.full():
                print("Buffer is full, waiting for consumer to consume...")
                time.sleep(random.randint(1, 3))
            else:
                # 生产一个随机数并添加到缓冲区
                num = random.randint(1, 100)
                buffer.put(num)
                print(f"Produced: {num}")
                time.sleep(1)

# 定义消费者类
class Consumer(threading.Thread):
    def run(self):
        while True:
            # 缓冲区为空,等待
            if buffer.empty():
                print("Buffer is empty, waiting for producer to produce...")
                time.sleep(random.randint(1, 3))
            else:
                # 从缓冲区取出一个随机数并消费
                num = buffer.get()
                print(f"Consumed: {num}")
                time.sleep(1)

# 创建生产者和消费者线程并启动
producer = Producer()
consumer = Consumer()
producer.start()
consumer.start()

使用Queue模块来创建一个大小为10的队列作为共享的缓冲区。生产者不断产生随机数并将其放入队列中,消费者不断从队列中取出随机数进行消费。使用Queue模块可以避免手动处理锁等线程同步机制,因为Queue提供了内置的线程安全机制。

四、集成三种模式的demo

首先,定义一个抽象产品类 Product,其中包含一个抽象方法 calculate_discount,用于计算折扣后的价格。

class Product(ABC):
    def __init__(self):
        self.price = None

    @abstractmethod
    def calculate_discount(self):
        pass

    def set_price(self, price):
        self.price = price

然后,创建具体的商品类 Book、Electronic,分别实现抽象方法

class Book(Product):
    def calculate_discount(self):
        # 具体的书籍折扣计算逻辑
        return 0.9  # 10% off

class Electronic(Product):
    def calculate_discount(self):
        # 具体的电子产品折扣计算逻辑
        return 0.8  # 20% off

接下来,定义一个抽象工厂类 ProductFactory,其中包含一个抽象方法 create_product,用于创建具体的产品对象。

class ProductFactory(ABC):
    @abstractmethod
    def create_product(self):
        pass

创建具体的工厂类 BookFactory、ElectronicFactory

class BookFactory(ProductFactory):
    def create_product(self):
        return Book()

class ElectronicFactory(ProductFactory):
    def create_product(self):
        return Electronic()

定义一个抽象折扣策略类 DiscountStrategy,其中包含一个抽象方法 apply_discount 用于应用折扣策略

class DiscountStrategy(ABC):
    @abstractmethod
    def apply_discount(self, product):
        pass

创建具体的折扣策略类 PercentOffStrategy 和 FixedAmountOffStrategy

class PercentOffStrategy(DiscountStrategy):
    def __init__(self, percent):
        self.percent = percent

    def apply_discount(self, product):
        discount = product.calculate_discount()
        discounted_price = product.price * (1 - discount * self.percent)
        return discounted_price

class FixedAmountOffStrategy(DiscountStrategy):
    def __init__(self, amount):
        self.amount = amount

    def apply_discount(self, product):
        discount = product.calculate_discount()
        discounted_price = product.price - (self.amount * discount)
        return discounted_price

定义一个生产者类 Producer,它生成不同类型的商品对象,并将其放入队列中

import time
from threading import Thread
from queue import Queue



class Producer(Thread):
    def __init__(self, queue, factory, price_max, price_min):
        super().__init__()
        self.queue = queue
        self.factory = factory
        self.price_max = price_max
        self.price_min = price_min

    def run(self):
        while True:
            # 生成商品,并放入队列中
            product = self.factory.create_product()
            price = random.randint(self.price_min, self.price_max)
            product.set_price(price)
            self.queue.put(product)
            time.sleep(5)  # 模拟生成商品的耗时操作

定义一个消费者类 Consumer,它从队列中获取商品对象,并根据折扣策略进行折扣操作

class Consumer(Thread):
    def __init__(self, queue, discount_strategy):
        super().__init__()
        self.queue = queue
        self.discount_strategy = discount_strategy

    def run(self):
        while True:
            # 从队列中获取商品,并应用折扣策略
            product = self.queue.get()

            discounted_price = self.discount_strategy.apply_discount(product)
            # 处理折扣后的价格逻辑
            print(f"Discounted price of {type(product).__name__}: {discounted_price}")

main函数

if __name__ == '__main__':
    queue = Queue()

    book_factory = BookFactory()
    producer1 = Producer(queue, book_factory, 50, 10)
    producer1.start()

    electronic_factory = ElectronicFactory()
    producer2 = Producer(queue, electronic_factory, 200, 100)
    producer2.start()

    percent_off_strategy = PercentOffStrategy(0.2)
    consumer1 = Consumer(queue, percent_off_strategy)
    consumer1.start()

    fixed_amount_off_strategy = FixedAmountOffStrategy(50)
    consumer2 = Consumer(queue, fixed_amount_off_strategy)
    consumer2.start()

完整代码

import random
import time
from threading import Thread
from queue import Queue
from abc import ABC, abstractmethod


class Product(ABC):
    def __init__(self):
        self.price = None

    @abstractmethod
    def calculate_discount(self):
        pass

    def set_price(self, price):
        self.price = price


class Book(Product):
    def calculate_discount(self):
        # 具体的书籍折扣计算逻辑
        return 0.9  # 10% off


class Electronic(Product):
    def calculate_discount(self):
        # 具体的电子产品折扣计算逻辑
        return 0.8  # 20% off


class ProductFactory(ABC):
    @abstractmethod
    def create_product(self):
        pass


class BookFactory(ProductFactory):
    def create_product(self):
        return Book()


class ElectronicFactory(ProductFactory):
    def create_product(self):
        return Electronic()


class DiscountStrategy(ABC):
    @abstractmethod
    def apply_discount(self, product):
        pass


class PercentOffStrategy(DiscountStrategy):
    def __init__(self, percent):
        self.percent = percent

    def apply_discount(self, product):
        discount = product.calculate_discount()
        discounted_price = product.price * (1 - discount * self.percent)
        return discounted_price


class FixedAmountOffStrategy(DiscountStrategy):
    def __init__(self, amount):
        self.amount = amount

    def apply_discount(self, product):
        discount = product.calculate_discount()
        discounted_price = product.price - (self.amount * discount)
        return discounted_price


class Producer(Thread):
    def __init__(self, queue, factory, price_max, price_min):
        super().__init__()
        self.queue = queue
        self.factory = factory
        self.price_max = price_max
        self.price_min = price_min

    def run(self):
        while True:
            # 生成商品,并放入队列中
            product = self.factory.create_product()
            price = random.randint(self.price_min, self.price_max)
            product.set_price(price)
            self.queue.put(product)
            time.sleep(5)  # 模拟生成商品的耗时操作


class Consumer(Thread):
    def __init__(self, queue, discount_strategy):
        super().__init__()
        self.queue = queue
        self.discount_strategy = discount_strategy

    def run(self):
        while True:
            # 从队列中获取商品,并应用折扣策略
            product = self.queue.get()

            discounted_price = self.discount_strategy.apply_discount(product)
            # 处理折扣后的价格逻辑
            print(f"Discounted price of {type(product).__name__}: {discounted_price}")


if __name__ == '__main__':
    queue = Queue()

    book_factory = BookFactory()
    producer1 = Producer(queue, book_factory, 50, 10)
    producer1.start()

    electronic_factory = ElectronicFactory()
    producer2 = Producer(queue, electronic_factory, 200, 100)
    producer2.start()

    percent_off_strategy = PercentOffStrategy(0.2)
    consumer1 = Consumer(queue, percent_off_strategy)
    consumer1.start()

    fixed_amount_off_strategy = FixedAmountOffStrategy(50)
    consumer2 = Consumer(queue, fixed_amount_off_strategy)
    consumer2.start()

参考

  • https://bbs.huaweicloud.com/blogs/281878

  • https://www.cnblogs.com/Zzbj/p/15778464.html

  • https://zhuanlan.zhihu.com/p/591928172

  • https://cloud.tencent.com/developer/article/1774687

推荐阅读:

我的2022届互联网校招分享

我的2021总结

浅谈算法岗和开发岗的区别

互联网校招研发薪资汇总

公众号:AI蜗牛车

保持谦逊、保持自律、保持进步

fdeb62d07fa85d82568e1433e9b2742f.jpeg

发送【蜗牛】获取一份《手把手AI项目》(AI蜗牛车著)

发送【1222】获取一份不错的leetcode刷题笔记

发送【AI四大名著】获取四本经典AI电子书

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/253757.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【谭浩强C语言:前八章编程题(多解)】

文章目录 第一章1. 求两个整数之和(p7) 第二章2. 求三个数中的较大值&#xff08;用函数&#xff09;(p14、p107)3.求123...n(求n的阶乘&#xff0c;用for循环与while循环)(P17)1.循环求n的阶乘2.递归求n的阶乘(n< 10) 4.有M个学生&#xff0c;输出成绩在80分以上的学生的学…

紫光FPGA DDR3 IP使用和注意事项(axi4协议)

紫光DDR3 IP使用 对于紫光ddr3 IP核的使用需要注意事情。 阅读ddr ip手册&#xff1a; 1、注意&#xff1a;对于写地址通道&#xff0c;axi_awvalid要一直拉高&#xff0c;axi_awready才会拉高。使用的芯片型号时PG2L100H-6FBG676&#xff0c;不同的型号IP核接口和axi的握手协…

计算机网络 网络层上 | IP数据报,IP地址,ICMP,ARP等

文章目录 1 网络层的两个层面2 网络协议IP2.1 虚拟互联网络2.2 IP地址2.2.1 固定分类编址方式2.2.2 无分类编制CIDR2.2.3 MAC地址和IP地址区别 2.3 地址解析协议ARP2.3.1 解析过程 2.4 IP数据报格式 3 IP层转发分组流程4 国际控制报文协议ICMP4.1 ICMP格式结构4.2 分类4.2.1 差…

【物联网】EMQX(二)——docker快速搭建EMQX 和 MQTTX客户端使用

一、前言 在上一篇文章中&#xff0c;小编向大家介绍了物联网必然会用到的消息服务器EMQ&#xff0c;相信大家也对EMQ有了一定的了解&#xff0c;那么接下来&#xff0c;小编从这篇文章正式开始展开对EMQ的学习教程&#xff0c;本章节来记录一下如何对EMQ进行安装。 二、使用…

系列八、约束

一、约束 1.1、概述 约束是作用于表中字段上的规则&#xff0c;用于限制存储在表中的数据&#xff0c;通过这种规则&#xff0c;可以保证数据库中数据的正确性、有效性和完整性。 1.2、分类 1.3、注意事项 约束是作用于表中字段上的&#xff0c;可以在创建表/修改表的时候添加…

vue3的大致使用

<template><div class"login_wrap"><div class"form_wrap"> <!-- 账号输入--> <el-form ref"formRef" :model"user" class"demo-dynamic" > <!--prop要跟属性名称对应-->…

2023 OADC:开放原子云社区正式启航,Curve、Kyuubi获奖

12月16-17日&#xff0c;2023开放原子开发者大会&#xff08;OADC&#xff09;在江苏省无锡市召开。大会首日&#xff0c;由网易数帆联合发起的“开放原子云社区”宣告成立&#xff0c;随后网易数帆资深云原生专家侯诗军分享了稳定性保障的前沿实践&#xff0c;Curve、Apache K…

引领位置服务驱动:腾讯地图 WebService 服务端 API 实用指南

&#x1f52d; 嗨&#xff0c;您好 &#x1f44b; 我是 vnjohn&#xff0c;在互联网企业担任 Java 开发&#xff0c;CSDN 优质创作者 &#x1f4d6; 推荐专栏&#xff1a;Spring、MySQL、Nacos、Java&#xff0c;后续其他专栏会持续优化更新迭代 &#x1f332;文章所在专栏&…

Web前端-JavaScript(js表达式)

文章目录 JavaScript基础第01天1.编程语言概述1.1 编程1.2 计算机语言1.2.1 机器语言1.2.2 汇编语言1.2.3 高级语言 1.4 翻译器 2.计算机基础2.1 计算机组成2.2 数据存储2.3 数据存储单位2.4 程序运行 3.初始JavaScript3.1 JavaScript 是什么3.2 JavaScript的作用3.3 HTML/CSS/…

修改npm源码解决服务端渲染环境中localstorage报错read properties of undefined (reading getItem)

现象&#xff1a; 这个问题是直接指向了我使用的第三方库good-storage&#xff0c;这是一个对localStorage/sessionStorage做了简单封装的库&#xff0c;因为项目代码有一个缓存cache.ts有用到 原因分析&#xff1a; 从表象上看是storage对象找不到getItem方法&#xff0c; 但…

大数据基础-测试过程

一、大数据&#xff1a; 大数据是一个大的数据集合&#xff0c;通过传统的计算技术无法处理。这些数据集的测试需要用各种工具、技术、框架进行处理。大数据涉及数据创建&#xff0c;存储、检索、分析&#xff0c;而且它在数量、多样性、速度都很出色。 二、大数据的测试类型…

【JAVA】CyclicBarrier源码解析以及示例

文章目录 前言CyclicBarrier源码解析以及示例主要成员变量核心方法 应用场景任务分解与合并应用示例 并行计算应用示例 游戏开发应用示例输出结果 数据加载应用示例 并发工具的协同应用示例 CyclicBarrier和CountDownLatch的区别循环性&#xff1a;计数器的变化&#xff1a;用途…

【Spark面试】Spark面试题答案

目录 1、spark的有几种部署模式&#xff0c;每种模式特点&#xff1f;&#xff08;☆☆☆☆☆&#xff09; 2、Spark为什么比MapReduce块&#xff1f;&#xff08;☆☆☆☆☆&#xff09; 3、简单说一下hadoop和spark的shuffle相同和差异&#xff1f;&#xff08;☆☆☆☆☆…

【HTML5、CSS3】新增特性总结!

文章目录 23 HTML5 新增特性23.1 语义化标签23.2 多媒体标签23.2.1 视频<video>标签23.2.2 音频<audio>标签 23.3 input属性值23.4 表单属性 24 CSS3 新增特性24.1 属性选择器24.2 结构伪类选择器24.2.1 选择第n个元素24.2.2 常用的6个结构伪类选择器 24.3 伪元素选…

Qt for Android设置安卓程序默认横屏+全屏

我的qt版本是5.14.1&#xff0c;网上查到的方法是&#xff0c;把编译出的build文件夹中的AndroidManifest.xml文件复制出来然后修改&#xff0c;然后把修改后的xml文件加入pro文件&#xff0c;语法为ANDROID_PACKAGE_SOURCE_DIR $$PWD/AndroidManifest.xml&#xff08;具体&am…

Window和Linux设置代理和取消代理(http_proxy)

前言 需要git clone下载项目的时候&#xff0c;一直clone不下来&#xff0c;则需要添加代理 特别注意&#xff0c;在图形界面中设置代理之后&#xff0c;还需要在终端命令行中设置&#xff0c;否则终端无法使用 1. Window 临时设置代理&#xff1a; export http_proxyhttp…

【运维笔记】Hyperf正常情况下Xdebug报错死循环解决办法

问题描述 在使用hyperf进行数据库迁移时&#xff0c;迁移报错&#xff1a; 查看报错信息&#xff0c;错误描述是Xdebug检测到死循环&#xff0c;可是打印的堆栈确实正常堆栈&#xff0c;没看到死循环。 寻求解决 gpt 说的跟没说一样。。 google一下 直接把报错信息粘贴上去…

LV.13 D5 uboot概述及SD卡启动盘制作 学习笔记

一、uboot概述 1.1 开发板启动过程 开发板上电后首先运行SOC内部iROM中固化的代码(BL0)&#xff0c;这段代码先对基本的软硬件环境(时钟等...)进行初始化&#xff0c;然后再检测拨码开关位置获取启动方式&#xff0c;然后再将对应存储器中的uboot搬移到内存&#xff0c;然后跳…

如何提高RAG增强的准确性

在一个典型的RAG应用开发中&#xff0c;必要的步骤为文档加载&#xff0c;文档拆分&#xff0c;向量化&#xff0c;向量存储。然后基于向量存储进行相似性查询&#xff0c;或基于向量距离的查询。这类查询就叫检索&#xff0c;LangChain所提供的对应组件就是检索器。 但这种方…

数据分析为何要学统计学(10)——如何进行比率检验

比率检验是通过样本推测某种事件的总体占比水平。要求事件仅有互斥的两种情况&#xff0c;即&#xff0c;概率分别为p与1-p。 比率检验分单样本和双样本两种情况&#xff0c;以下我们分别介绍。 1. 单样本比率检验 形如这样的问题&#xff1a;“小学生近视比例日益提高&#…