# 【笔记】大话设计模式21-23

news2024/5/18 1:46:18

【笔记】大话设计模式21-23

文章目录

  • 【笔记】大话设计模式21-23
  • 单例模式
      • 21.1 Example
      • 21.2 定义
      • 21.3 Show me the code
        • 一般单例代码(**懒汉模式**)
        • 静态初始化(**饿汉模式**)
      • 21.4 总结
  • 22 桥接模式
      • 22.1 Example
      • 22.2 定义
      • 22.3 Show me the code
      • 22.4 总结
  • 23 命令模式
      • 23.1 Example
      • 23.2 定义
      • 23.3 Show me the code
      • 23.4 总结

单例模式

21.1 Example

这个很好理解,每个人都是唯一的实体,不允许影分身术,分裂成多个你出来。

所以,电脑和手机上,很多软件,都只能打开1个窗口,重复打开,也只会调用那个唯一的单例。

一般C#里,定义一个全局静态变量即可,每次判断这个变量有没有存在或者窗体有没有Disposed,存在则已经生成过单例了。

picture source : Refactoring.Guru

21.2 定义

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

21.3 Show me the code

一般单例代码(懒汉模式)

代码中lock (syncRoot)是将当前变量锁定,阻塞其他线程;

该锁前后进行了2次判断,是因为如果在多线程程序中,两个进行同时判断了第一个if语句,则会同时进入加锁代码中,因为lock机制,只允许1个线程进入,另一个阻塞,所以当第一个线程创建实例后,第二个线程即便在lock中,也不会再次创建实例。

这种做法就是Double-Check Locking(双重锁定)。

class Singleton
{
    // 私有静态变量
    private static Singleton instance;  
    // 初始化一个锁变量
    private static readonly object syncRoot = new object();
    // 私有构造函数,不允许外部实例化
    private Singleton()
    {
    }

    public static Singleton GetInstance()
    {
        if (instance == null)
        {
            lock (syncRoot)
            {
                if (instance == null)
                {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

静态初始化(饿汉模式

C#与公共语言运行库提供了“静态初始化”的方法,不需要编写线程安全代码,即可解决多线程环境下不安全问题。

解决了2个问题:全局访问、实例化控制

instance变量标记为readonly,只能在静态初始化期间或在类构造函数中分配变量,实例被加载时就将自己实例化

// sealed 阻止派生类,因为派生类可能会增加实例
public sealed class Singleton
{
    // 在第一次引用类的任何成员时创建实例。公共语言运行库负责处理变量初始化
	private static readonly Singleton instance = new Singletion();
	private Singleton(){ }
	public static Singleton GetInstance()
	{
		return instance;
    }
}

21.4 总结

  • 饿汉模式:静态初始化的方式,类一加载就实例化对象,需要提前占用系统资源。
  • 懒汉模式:面临多线程访问的安全性问题,需要双重锁定,需要的时候才实例化。
  • 抽象工厂模式生成器模式原型模式都可以用单例实现。

22 桥接模式

22.1 Example

在阿三还在上大学的时候,那时候手机还是诺基亚、摩托罗拉等品牌兴盛的时候,那时候,不同手机的软件不能通用,需要去手机品牌官网指定的网站上下载,哪怕下载同一款软件。

现在安卓机就是这样,大家都是使用安卓的操作系统,接口都一样的,想要开发软件,就在统一接口下,开发自己的软件或者适配自己的机型就行了。

picture source : Refactoring.Guru

22.2 定义

合成/聚合复用原则(CARP):尽量使用合成/聚合,尽量不要使用类继承。

桥接模式(Bridge),将抽象部分与它的实现部分分离,使它们可以独立地变化。

22.3 Show me the code

class Program
{
    static void Main(string[] args)
    {
        Abstraction ab = new RefinedAbstraction();

        ab.SetImplementor(new ConcreteImplementorA());
        ab.Operation();

        ab.SetImplementor(new ConcreteImplementorB());
        ab.Operation();

        Console.Read();
    }
}

class Abstraction
{
    protected Implementor implementor;

    public void SetImplementor(Implementor implementor)
    {
        this.implementor = implementor;
    }

    public virtual void Operation()
    {
        implementor.Operation();
    }

}

class RefinedAbstraction : Abstraction
{
    public override void Operation()
    {
        implementor.Operation();
    }
}

abstract class Implementor
{
    public abstract void Operation();
}

class ConcreteImplementorA : Implementor
{
    public override void Operation()
    {
        Console.WriteLine("具体实现A的方法执行");
    }
}

class ConcreteImplementorB : Implementor
{
    public override void Operation()
    {
        Console.WriteLine("具体实现B的方法执行");
    }
}

22.4 总结

  • 聚合表示一种弱的拥有关系,体现A对象可以包含B对象,但是B对象不是A对象的一部分;

  • 合成表示一种强的拥有关系,体现了严格的部分和整体的关系,部分和整体的生命周期一样;

  • 桥接模式就是实现系统可能有多角度分类,每一种分类可能都有变化,就把多角度分离出来让其对立变化,减少耦合。就像电脑硬盘、显卡、内存条等设备,都可以独立插拔安装,选用不同品牌的硬件。

    picture source : Refactoring.Guru

    其实就是实现上图的思维模式转变,将原本通过继承等耦合方式实现的重量子类,变成独立的维度类,降低耦合,同时增加了每个维度的类的扩展空间。

23 命令模式

亦称: 动作、事务、Action、Transaction、Command

23.1 Example

大头家旁边开了一家烧饼店,店家是小本经营,就一个摊位,没有座位等,大家排队买烧饼,买完就带回去吃。

但是这样有个缺陷,就是大家围成一圈买烧饼,纷纷告诉老板要什么口味的烧饼,老板一个人也记不住,很容易把刚烤好的烧饼给了后来的人,先来的人没买到,导致了和老板的冲突。

这就是“行为请求者”(买烧饼的人)和“行为实现者”(烧饼店老板)的紧耦合。

反观看有点餐机的店铺就不同了,每个客人点餐后,点餐请求加入到请求队列中,而且包含详细的点餐内容,店面老板按照请求队列做餐即可。老板都不用知道谁点的什么内容。这就实现了解耦。

picture source : Refactoring.Guru

23.2 定义

命令模式(Command):将一个请求封装成一个对象,从而使你可以用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。

23.3 Show me the code

class Program
{
    static void Main(string[] args)
    {
        //开店前的准备
        Barbecuer boy = new Barbecuer();
        Command bakeMuttonCommand1 = new BakeMuttonCommand(boy);
        Command bakeMuttonCommand2 = new BakeMuttonCommand(boy);
        Command bakeChickenWingCommand1 = new BakeChickenWingCommand(boy);
        Waiter girl = new Waiter();

        //开门营业 顾客点菜
        girl.SetOrder(bakeMuttonCommand1);
        girl.SetOrder(bakeMuttonCommand2);
        girl.SetOrder(bakeChickenWingCommand1);

        //点菜完闭,通知厨房
        girl.Notify();

        Console.Read();

    }
}

//服务员
public class Waiter
{
    private IList<Command> orders = new List<Command>();

    //设置订单
    public void SetOrder(Command command)
    {
        if (command.ToString() == "命令模式.BakeChickenWingCommand")
        {
            Console.WriteLine("服务员:鸡翅没有了,请点别的烧烤。");
        }
        else
        {
            orders.Add(command);
            Console.WriteLine("增加订单:" + command.ToString() + "  时间:" + DateTime.Now.ToString());
        }
    }

    //取消订单
    public void CancelOrder(Command command)
    {
        orders.Remove(command);
        Console.WriteLine("取消订单:" + command.ToString() + "  时间:" + DateTime.Now.ToString());
    }

    //通知全部执行
    public void Notify()
    {
        foreach (Command cmd in orders)
        {
            cmd.ExcuteCommand();
        }
    }
}

//抽象命令
public abstract class Command
{
    protected Barbecuer receiver;

    public Command(Barbecuer receiver)
    {
        this.receiver = receiver;
    }

    //执行命令
    abstract public void ExcuteCommand();
}

//烤羊肉串命令
class BakeMuttonCommand : Command
{
    public BakeMuttonCommand(Barbecuer receiver)
        : base(receiver)
        { }

    public override void ExcuteCommand()
    {
        receiver.BakeMutton();
    }
}

//烤鸡翅命令
class BakeChickenWingCommand : Command
{
    public BakeChickenWingCommand(Barbecuer receiver)
        : base(receiver)
        { }

    public override void ExcuteCommand()
    {
        receiver.BakeChickenWing();
    }
}

//烤肉串者
public class Barbecuer
{
    public void BakeMutton()
    {
        Console.WriteLine("烤羊肉串!");
    }

    public void BakeChickenWing()
    {
        Console.WriteLine("烤鸡翅!");
    }
}

23.4 总结

  • 优点:
    • 命令行模式能较容易地设计一个命令队列;
    • 较容易地将命令记入日志;
    • 允许接受请求的一方决定是否否决请求;
    • 容易实现对请求的撤销、重做和延迟执行,比如数据回滚操作;
    • 加入新命令不影响其他类;
    • 将请求操作的对象与指导执行对象分开。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Code for VeLO 1: Training Versatile Learned Optimizers by Scaling Up

Code for VeLO 1: Training Versatile Learned Optimizers by Scaling Up 这篇文章将介绍一下怎么用VeLO进行训练。 这篇文章基于https://colab.research.google.com/drive/1-ms12IypE-EdDSNjhFMdRdBbMnH94zpH#scrollToRQBACAPQZyB-&#xff0c;将介绍使用learned optimizer in…

入门力扣自学笔记230 C++ (题目编号:2293)

2293. 极大极小游戏 题目&#xff1a; 给你一个下标从 0 开始的整数数组 nums &#xff0c;其长度是 2 的幂。 对 nums 执行下述算法&#xff1a; 设 n 等于 nums 的长度&#xff0c;如果 n 1 &#xff0c;终止 算法过程。否则&#xff0c;创建 一个新的整数数组 newNums …

【Python百日进阶-数据分析】Day226 - plotly的仪表盘go.Indicator()

文章目录一、语法二、参数三、返回值四、实例4.1 Bullet Charts子弹图4.1.1 基本子弹图4.1.2 添加步骤和阈值4.1.3 自定义子弹4.1.4 多子弹4.2 径向仪表图4.2.1 基本仪表4.2.2 添加步骤、阈值和增量4.2.3 自定义仪表图4.3 组合仪表图4.3.1 组合仪表图4.3.2 单角量规图4.3.3 子弹…

Android 深入系统完全讲解(19)

技术的学习关键点 是什么&#xff1f;思路。 而我这里分享一个学习的经典路线&#xff0c;先厘清总框架&#xff0c;找到思路&#xff0c;然后再逐步击破。 这里关于音视频的就是&#xff1a; 总体分为几部分&#xff1a; 1 绘制 2 编解码格式 3 Android 平台的 FFmpeg 开源移…

Compressed Sensing——从零开始压缩感知

Problem 考虑一个线性方程组求解问题&#xff1a; Axb(1)A x b \tag{1}Axb(1) 其中&#xff0c;A∈RmnA \in\mathbb R^{m\times n}A∈Rmn&#xff0c;x∈Rn1x \in\mathbb R^{n\times 1}x∈Rn1&#xff0c;b∈Rm1b \in\mathbb R^{m\times 1}b∈Rm1且m≪nm \ll nm≪n 这是一个…

【C++11】—— lambda表达式

目录 一、lambda表达式的简介 二、lambda表达式的基本语法 三、lambda表达式的使用方法 四、lambda表达式的底层原理 一、lambda表达式的简介 lambda表达式就类似于仿函数&#xff0c;相比仿函数要更加的简洁&#xff0c;我们看一下下面的代码&#xff1a; //商品类 struct…

【项目实战】使用MybatisPlus乐观锁插件功能

一、背景 当要更新一条记录时&#xff0c;希望这条记录没有被别人更新&#xff0c;可以考虑使用MybatisPlus乐观锁插件功能来实现以上需求。 二、乐观锁介绍 2.1 乐观锁是什么&#xff1f; 乐观锁是一种乐观思想&#xff0c;即认为读多写少&#xff0c;遇到并发的可能性低&…

使用ASM框架创建ClassVisitor时遇到IllegalArgumentException的一种可能解决办法

背景 ASM是java语言中最为广泛使用的插装框架&#xff0c;其优点在于可以动态地在运行时改变java系统的行为&#xff0c;加入我们自己的逻辑。在软件测试领域应用广泛。但是其使用难度很高&#xff0c;一方面使用asm框架需要对java底层知识有较高的了解&#xff0c;另一方面网…

网页共享电脑屏幕与播放(带声音)

这次项目我们是写的一个课堂辅助软件的网页版&#xff0c;其中有一个功能感觉能作为我们项目的一个亮点&#xff0c;就是直播功能&#xff0c;在之前并没有写过这个东西。虽然现在这个功能还不知道怎么写&#xff0c;但是它的流程终归是利用视频流将本地的视频给共享出去&#…

Verilog:【8】基于FPGA实现SD NAND FLASH的SPI协议读写

碎碎念&#xff1a; 终于熬过了期末周&#xff0c;可以开始快乐的开发之旅了。 这一期作为一千粉后的首篇博客&#xff0c;由于之后项目会涉及到相关的部分&#xff0c;因此介绍的是使用FPGA实现SD NAND FLASH的读写操作&#xff0c;以雷龙科技提供的SD NAND FLASH样品为例&…

实证分析权重系数计算大全

在实际研究中&#xff0c;权重计算是一种常见的分析方法&#xff0c;需要结合数据的特征情况进行选择&#xff0c;比如数据之间的波动性是一种信息量&#xff0c;那么可考虑使用CRITIC权重法或信息量权重法&#xff1b;也或者专家打分数据&#xff0c;那么可使用AHP层次法或优序…

直观感受PromQL及其数据类型

由于PromQL内容较多&#xff0c;将内容分为三篇文章讲述&#xff1a; 一、直观感受PromQL及其数据类型 二、PromQL之选择器和运算符 三、PromQL之函数 想必都知道要使用Msql&#xff0c;必须会用SQL&#xff0c;同样要使用Prometheus 就要掌握PromQL&#xff08;Prometheus Que…

【链表】leetcode142.环形链表II(C/C++/Java/Js)

leetcode142.环形链表II1 题目2 思路2.1 判断链表是否有环--快慢指针法2.2 如果有环&#xff0c;如何找到这个环的入口2.3 补充3 代码3.1 C版本3.2 C版本3.3 Java版本3.4 JavaScript版本4 总结1 题目 题源链接 给定一个链表的头节点 head &#xff0c;返回链表开始入环的第一个…

软测复习05:基于质量特征的测试

作者&#xff1a;非妃是公主 专栏&#xff1a;《软件测试》 个性签&#xff1a;顺境不惰&#xff0c;逆境不馁&#xff0c;以心制境&#xff0c;万事可成。——曾国藩 文章目录性能测试压力测试容量测试健壮性测试安全性测试可靠性测试恢复性测试协议一致性测试兼容性测试安装…

【数据结构】保姆级单链表教程(概念、分类与实现)

目录 &#x1f34a;前言&#x1f34a;&#xff1a; &#x1f348;一、链表概述&#x1f348;&#xff1a; 1.链表的概念及结构&#xff1a; 2.链表存在的意义&#xff1a; &#x1f353;二、链表的分类&#x1f353;&#xff1a; &#x1f95d;三、单链表的实现&#x1f…

​盘点几款国内外安全稳定的域名解析平台​

众所周知&#xff0c;有了域名后想建站使用&#xff0c;必须要先解析域名。域名使用注册商一般会提供域名解析服务&#xff0c;这虽然为用户提供了方便&#xff0c;但功能大多有限&#xff0c;使用第三方域名解析平台就成了非常必要的选择。今天&#xff0c;小编就为大家盘点几…

计算机视觉OpenCv学习系列:第四部分、键盘+鼠标响应操作

第四部分、键盘鼠标响应操作第一节、键盘响应操作1.键盘响应事件2.键盘响应3.代码练习与测试第二节、鼠标操作与响应1.鼠标事件与回调2.鼠标操作3.代码练习与测试学习参考第一节、键盘响应操作 键盘响应中有一个函数叫做waitKey&#xff0c;所有的获取键盘键值都是通过waitKey…

【经典笔试题】动态内存管理

test1&#xff1a;void GetMemory(char* p) {p (char*)malloc(100); } void Test(void) {char* str NULL;GetMemory(str);strcpy(str, "hello world");printf(str); }int main() {Test();return 0; }请问执行上面代码&#xff0c;会出现什么结果&#xff1f;解析&a…

7. R语言【独立性检验】:卡方独立性检验、Fisher精确检验 、Cochran-Mantel-Haenszel检验

文章目录1. 卡方检验2. 费希尔精确检验&#xff08;Fisher Exact Test&#xff09;3. Cochran-Mantel-Haenszel检验独立性检验&#xff1a;用来判断变量之间相关性的方法&#xff0c;如果两个变量彼此独立&#xff0c;那么两者统计上就是不相关的 1. 卡方检验 可以使用chisq.…

Java面向对象之多态、内部类、常用API

目录面向对象之三大特性之三&#xff1a;多态多态的概述、多态的形式多态的好处多态下引用数据类型的类型转换多态的综合案例内部类内部类概述内部类之一&#xff1a;静态内部类内部类之二&#xff1a;成员内部类内部类之三&#xff1a;局部内部类内部类之四&#xff1a;匿名内…