C#面试常考随笔12:游戏开发中常用的设计模式【C#面试题(中级篇)补充】

C#面试题(中级篇),详细讲解,帮助你深刻理解,拒绝背话术!-CSDN博客

简单工厂模式

优点:

根据条件有工厂类直接创建具体的产品

客户端无需知道具体的对象名字,可以通过配置文件创建,灵活。

缺点:

每增加一个对象,就需要在工厂添加新的产品,修改工厂逻辑,不易拓展


 

using System;// 定义产品的抽象基类
public abstract class Product
{public abstract void Use();
}// 具体产品类A
public class ConcreteProductA : Product
{public override void Use(){Console.WriteLine("Using ConcreteProductA");}
}// 具体产品类B
public class ConcreteProductB : Product
{public override void Use(){Console.WriteLine("Using ConcreteProductB");}
}// 简单工厂类
public class SimpleFactory
{public static Product CreateProduct(string type){switch (type){case "A":return new ConcreteProductA();case "B":return new ConcreteProductB();default:throw new ArgumentException("Invalid product type");}}
}class Program
{static void Main(){Product productA = SimpleFactory.CreateProduct("A");productA.Use();Product productB = SimpleFactory.CreateProduct("B");productB.Use();}
}

工厂方法模式

解决了简单工厂的 开放-关闭原则

不同的子类由工厂子类创建

但是对象数量会很多

抽象工厂

抽象工厂:(相当于有多个工厂)不同厂商生产的同一产品,产品拥有相同的结构,区别在于不同的厂商和动作的细节。比如多个电脑工厂,生产不同品牌的电脑,电脑有多个配件,每个工厂都生产这些配件()。

抽象工厂有产品,继承的工厂生产对应厂商的产品。


using System;// 定义产品A的抽象基类
public abstract class AbstractProductA
{public abstract void UseA();
}// 具体产品A1
public class ConcreteProductA1 : AbstractProductA
{public override void UseA(){Console.WriteLine("Using ConcreteProductA1");}
}// 具体产品A2
public class ConcreteProductA2 : AbstractProductA
{public override void UseA(){Console.WriteLine("Using ConcreteProductA2");}
}// 定义产品B的抽象基类
public abstract class AbstractProductB
{public abstract void UseB();
}// 具体产品B1
public class ConcreteProductB1 : AbstractProductB
{public override void UseB(){Console.WriteLine("Using ConcreteProductB1");}
}// 具体产品B2
public class ConcreteProductB2 : AbstractProductB
{public override void UseB(){Console.WriteLine("Using ConcreteProductB2");}
}// 抽象工厂类
public abstract class AbstractFactory
{public abstract AbstractProductA CreateProductA();public abstract AbstractProductB CreateProductB();
}// 具体工厂类1,负责创建产品A1和产品B1
public class ConcreteFactory1 : AbstractFactory
{public override AbstractProductA CreateProductA(){return new ConcreteProductA1();}public override AbstractProductB CreateProductB(){return new ConcreteProductB1();}
}// 具体工厂类2,负责创建产品A2和产品B2
public class ConcreteFactory2 : AbstractFactory
{public override AbstractProductA CreateProductA(){return new ConcreteProductA2();}public override AbstractProductB CreateProductB(){return new ConcreteProductB2();}
}class Program
{static void Main(){AbstractFactory factory1 = new ConcreteFactory1();AbstractProductA productA1 = factory1.CreateProductA();AbstractProductB productB1 = factory1.CreateProductB();productA1.UseA();productB1.UseB();AbstractFactory factory2 = new ConcreteFactory2();AbstractProductA productA2 = factory2.CreateProductA();AbstractProductB productB2 = factory2.CreateProductB();productA2.UseA();productB2.UseB();}
}

观察者模式(发布-订阅)

和事件系统的逻辑基本一致

一个发布者,多个订阅者。把观察者注册进去。下图是简易的事件系统

using System;
using System.Collections.Generic;// 定义观察者接口
public interface IObserver
{void Update(string message);
}// 定义主题接口
public interface ISubject
{void RegisterObserver(IObserver observer);void RemoveObserver(IObserver observer);void NotifyObservers();
}// 具体主题类
public class ConcreteSubject : ISubject
{private List<IObserver> observers = new List<IObserver>();private string message;public void RegisterObserver(IObserver observer){observers.Add(observer);}public void RemoveObserver(IObserver observer){observers.Remove(observer);}public void NotifyObservers(){foreach (var observer in observers){observer.Update(message);}}public void SetMessage(string newMessage){message = newMessage;NotifyObservers();}
}// 具体观察者类
public class ConcreteObserver : IObserver
{private string name;public ConcreteObserver(string name){this.name = name;}public void Update(string message){Console.WriteLine($"{name} received message: {message}");}
}class Program
{static void Main(){// 创建主题ConcreteSubject subject = new ConcreteSubject();// 创建观察者ConcreteObserver observer1 = new ConcreteObserver("Observer 1");ConcreteObserver observer2 = new ConcreteObserver("Observer 2");// 注册观察者subject.RegisterObserver(observer1);subject.RegisterObserver(observer2);// 主题发布消息subject.SetMessage("New message from the subject!");// 移除一个观察者subject.RemoveObserver(observer2);// 主题再次发布消息subject.SetMessage("Another message from the subject!");}
}

状态模式

特点:

和FSM有限状态机是相似逻辑,可以说FSM是状态模式的运用

将状态相关的行为封装到不同的状态类中,使得状态的变化和对象行为的变化能够独立进行,符合开闭原则。

游戏中角色的不同状态(如奔跑、跳跃、攻击等)可用状态模式实现,每个状态有不同行为逻辑

using System;// 定义状态接口
public interface IState
{void Handle(Context context);
}// 具体状态类A
public class ConcreteStateA : IState
{public void Handle(Context context){Console.WriteLine("Handling state A. Transitioning to state B.");context.State = new ConcreteStateB();}
}// 具体状态类B
public class ConcreteStateB : IState
{public void Handle(Context context){Console.WriteLine("Handling state B. Transitioning to state A.");context.State = new ConcreteStateA();}
}// 上下文类
public class Context
{private IState state;public Context(IState initialState){this.state = initialState;}public IState State{get { return state; }set{state = value;Console.WriteLine($"State changed to {state.GetType().Name}");}}public void Request(){state.Handle(this);}
}class Program
{static void Main(){// 创建初始状态IState initialState = new ConcreteStateA();// 创建上下文对象Context context = new Context(initialState);// 执行请求,触发状态转换context.Request();context.Request();}
}
  1. IState 接口:定义了状态的行为方法 Handle,具体的状态类需要实现该方法。
  2. ConcreteStateA 和 ConcreteStateB 类:实现了 IState 接口,分别代表不同的状态,在 Handle 方法中处理当前状态的逻辑,并可以进行状态的转换。
  3. Context 类:维护一个当前状态的引用 state,通过 Request 方法调用当前状态的 Handle 方法,同时提供了 State 属性用于改变当前状态。

优点

  • 可维护性高:将不同状态的行为封装到不同的状态类中,使得代码结构清晰,易于理解和维护。当需要添加新的状态时,只需要创建一个新的状态类并实现相应的行为,而不需要修改现有的代码。
  • 可扩展性强:符合开闭原则,对扩展开放,对修改关闭。可以方便地添加新的状态和状态转换逻辑,而不会影响其他状态类和上下文类。
  • 状态转换清晰:状态的转换逻辑集中在状态类中,使得状态转换的规则更加清晰,易于管理和调试。

缺点

  • 类的数量增加:每个状态都需要一个对应的状态类,当状态较多时,会导致类的数量增加,增加了系统的复杂性。
  • 状态之间的耦合:状态类之间可能存在一定的耦合,特别是在状态转换时,一个状态类可能需要知道其他状态类的信息,这可能会影响代码的可维护性。

 装饰器模式

动态地给对象添加额外职责。游戏中给角色添加装备或增益效果可使用装饰器模式

 

using System;// 定义组件接口
public interface IComponent
{void Operation();
}// 具体组件类
public class ConcreteComponent : IComponent
{public void Operation(){Console.WriteLine("ConcreteComponent: Performing basic operation.");}
}// 装饰器抽象类
public abstract class Decorator : IComponent
{protected IComponent component;public Decorator(IComponent component){this.component = component;}public virtual void Operation(){if (component != null){component.Operation();}}
}// 具体装饰器类A
public class ConcreteDecoratorA : Decorator
{public ConcreteDecoratorA(IComponent component) : base(component){}public override void Operation(){base.Operation();AddedBehaviorA();}private void AddedBehaviorA(){Console.WriteLine("ConcreteDecoratorA: Adding additional behavior A.");}
}// 具体装饰器类B
public class ConcreteDecoratorB : Decorator
{public ConcreteDecoratorB(IComponent component) : base(component){}public override void Operation(){base.Operation();AddedBehaviorB();}private void AddedBehaviorB(){Console.WriteLine("ConcreteDecoratorB: Adding additional behavior B.");}
}class Program
{static void Main(){// 创建具体组件IComponent component = new ConcreteComponent();// 使用具体装饰器A包装组件IComponent decoratedComponentA = new ConcreteDecoratorA(component);// 使用具体装饰器B包装经过装饰器A包装的组件IComponent decoratedComponentB = new ConcreteDecoratorB(decoratedComponentA);// 调用操作方法decoratedComponentB.Operation();}
}

优点:

  • 装饰类和被装饰类可以独立发展,不会相互耦合。

  • 装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。

缺点:

  • 多层装饰比较复杂。

适配器模式

将一个类的接口转换成客户希望的另一个接口。适配器模式主要有类适配器模式和对象适配器模式两种实现方式。

对象适配器:相当于把对象作为一个属性

类适配器:相当于继承

对象:

using System;// 目标接口,客户端所期望的接口
public interface ITarget
{void Request();
}// 适配者类,需要被适配的类
public class Adaptee
{public void SpecificRequest(){Console.WriteLine("Adaptee: Specific request.");}
}// 适配器类,实现目标接口并持有适配者对象
public class Adapter : ITarget
{private Adaptee adaptee;public Adapter(Adaptee adaptee){this.adaptee = adaptee;}public void Request(){adaptee.SpecificRequest();}
}class Program
{static void Main(){// 创建适配者对象Adaptee adaptee = new Adaptee();// 创建适配器对象并传入适配者对象ITarget adapter = new Adapter(adaptee);// 通过适配器调用目标接口方法adapter.Request();}
}

类:

using System;// 目标接口
public interface ITargetClassAdapter
{void Request();
}// 适配者类
public class AdapteeClassAdapter
{public void SpecificRequest(){Console.WriteLine("AdapteeClassAdapter: Specific request.");}
}// 适配器类,继承适配者类并实现目标接口
public class ClassAdapter : AdapteeClassAdapter, ITargetClassAdapter
{public void Request(){SpecificRequest();}
}class ProgramClassAdapter
{static void Main(){// 创建类适配器对象ITargetClassAdapter adapter = new ClassAdapter();// 通过适配器调用目标接口方法adapter.Request();}
}

优点

  1. 提高复用性:可以让原本不兼容的类一起工作,使得一些已经存在的类可以被复用,无需对其进行修改。例如,当你有一个旧的库,其接口与新系统不兼容时,使用适配器模式可以将其集成到新系统中。

  2. 灵活性和扩展性:适配器模式符合开闭原则,当需要适配新的类时,只需要创建新的适配器类,而不需要修改现有的代码。

  3. 解耦性:将客户端和适配者解耦,客户端只需要与目标接口交互,而不需要关心适配者的具体实现。

缺点

  1. 增加系统复杂度:引入适配器类会增加系统的类数量和代码复杂度,特别是当存在多个适配器时,可能会使系统变得难以理解和维护。

  2. 过多使用会导致代码混乱:如果过度使用适配器模式,可能会导致系统中存在大量的适配器类,使得代码结构变得混乱,难以把握整体的设计意图。

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

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

相关文章

数字人|通过语音和图片来创建高质量的视频

简介 arXiv上的计算机视觉领域论文&#xff1a; AniPortrait: Audio-Driven Synthesis of Photorealistic Portrait Animation AniPortrait&#xff1a;照片级真实感肖像动画的音频驱动合成 核心内容围绕一种新的人像动画合成框架展开。 研究内容 提出 AniPortrait 框架&a…

数据结构实战之线性表(三)

目录 1.顺序表释放 2.顺序表增加空间 3.合并顺序表 4.线性表之链表实现 1.项目结构以及初始代码 2.初始化链表(不带头结点) 3.链表尾部插入数据并显示 4.链表头部插入数据 5.初始化链表&#xff08;带头结点&#xff09; 6.带头结点的链表头部插入数据并显示 7.带头结…

Docker使用指南(一)——镜像相关操作详解(实战案例教学,适合小白跟学)

目录 1.镜像名的组成 2.镜像操作相关命令 镜像常用命令总结&#xff1a; 1. docker images 2. docker rmi 3. docker pull 4. docker push 5. docker save 6. docker load 7. docker tag 8. docker build 9. docker history 10. docker inspect 11. docker prune…

C++基础day1

前言&#xff1a;谢谢阿秀&#xff0c;指路阿秀的学习笔记 一、基础语法 1.构造和析构: 类的构造函数是一种特殊的函数&#xff0c;在创建一个新的对象时调用。类的析构函数也是一种特殊的函数&#xff0c;在删除所创建的对象时调用。 构造顺序&#xff1a;父类->子类 析…

尝试ai生成figma设计

当听到用ai 自动生成figma设计时&#xff0c;不免好奇这个是如何实现的。在查阅了不少资料后&#xff0c;有了一些想法。参考了&#xff1a;在figma上使用脚本自动生成色谱 这篇文章提供的主要思路是&#xff1a;可以通过脚本的方式构建figma设计。如果我们使用ai 生成figma脚本…

【PyQt】pyqt小案例实现简易文本编辑器

pyqt小案例实现简易文本编辑器 分析 实现了一个简单的文本编辑器&#xff0c;使用PyQt5框架构建。以下是代码的主要功能和特点&#xff1a; 主窗口类 (MyWindow): 继承自 QWidget 类。使用 .ui 文件加载用户界面布局。设置窗口标题、状态栏消息等。创建菜单栏及其子菜单项&…

【电脑系统】电脑突然(蓝屏)卡死发出刺耳声音

文章目录 前言问题描述软件解决方案尝试硬件解决方案尝试参考文献 前言 在 更换硬盘 时遇到的问题&#xff0c;有时候只有卡死没有蓝屏 问题描述 更换硬盘后&#xff0c;电脑用一会就卡死&#xff0c;蓝屏&#xff0c;显示蓝屏代码 UNEXPECTED_STORE_EXCEPTION 软件解决方案…

【大模型LLM面试合集】大语言模型架构_Transformer架构细节

Transformer架构细节 1.Transformer各个模块的作用 &#xff08;1&#xff09;Encoder模块 经典的Transformer架构中的Encoder模块包含6个Encoder Block. 每个Encoder Block包含两个⼦模块, 分别是多头⾃注意⼒层, 和前馈全连接层. 多头⾃注意⼒层采⽤的是⼀种Scaled Dot-Pr…

【华为OD-E卷 - 113 跳格子2 100分(python、java、c++、js、c)】

【华为OD-E卷 - 跳格子2 100分&#xff08;python、java、c、js、c&#xff09;】 题目 小明和朋友玩跳格子游戏&#xff0c;有 n 个连续格子组成的圆圈&#xff0c;每个格子有不同的分数&#xff0c;小朋友可以选择以任意格子起跳&#xff0c;但是不能跳连续的格子&#xff…

国防科大:双目标优化防止LLM灾难性遗忘

&#x1f4d6;标题&#xff1a;How to Complete Domain Tuning while Keeping General Ability in LLM: Adaptive Layer-wise and Element-wise Regularization &#x1f310;来源&#xff1a;arXiv, 2501.13669 &#x1f31f;摘要 &#x1f538;大型语言模型&#xff08;LLM…

Verilog基础(一):基础元素

verilog基础 我先说,看了肯定会忘,但是重要的是这个过程,我们知道了概念,知道了以后在哪里查询。语法都是术,通用的概念是术。所以如果你有相关的软件编程经验,那么其实开启这个学习之旅,你会感受到熟悉,也会感受到别致。 入门 - 如何开始 欢迎来到二进制的世界,数字…

多无人机--强化学习

这个是我对于我的大创项目的构思&#xff0c;随着时间逐渐更新 项目概要 我们的项目平台来自挑战杯揭绑挂帅的无人机对抗项目&#xff0c;但是在由于时间原因&#xff0c;并未考虑强化学习&#xff0c;所以现在通过大创项目来弥补遗憾 我们项目分为三部分&#xff0c;分为虚…

Python----Python高级(并发编程:进程Process,多进程,进程间通信,进程同步,进程池)

一、进程Process 拥有自己独立的堆和栈&#xff0c;既不共享堆&#xff0c;也不共享栈&#xff0c;进程由操作系统调度&#xff1b;进程切换需要的资源很最大&#xff0c;效率低。 对于操作系统来说&#xff0c;一个任务就是一个进程&#xff08;Process&#xff09;&#xff…

在Mapbox GL JS中“line-pattern”的使用详解

在Mapbox GL JS中&#xff0c;line-pattern 是一种用于在地图上绘制带有图案的线条的样式属性。通过 line-pattern&#xff0c;你可以使用自定义的图像作为线条的图案&#xff0c;而不是使用纯色或渐变。 1. 基本概念 line-pattern: 该属性允许你指定一个图像作为线条的图案。…

C++ Primer 算术运算符

欢迎阅读我的 【CPrimer】专栏 专栏简介&#xff1a;本专栏主要面向C初学者&#xff0c;解释C的一些基本概念和基础语言特性&#xff0c;涉及C标准库的用法&#xff0c;面向对象特性&#xff0c;泛型特性高级用法。通过使用标准库中定义的抽象设施&#xff0c;使你更加适应高级…

【大数据技术】本机PyCharm远程连接虚拟机Python

本机PyCharm远程连接虚拟机Python 注意:本文需要使用PyCharm专业版。 pycharm-professional-2024.1.4VMware Workstation Pro 16CentOS-Stream-10-latest-x86_64-dvd1.iso写在前面 本文主要介绍如何使用本地PyCharm远程连接虚拟机,运行Python脚本,提高编程效率。 注意: …

MyBatis-Plus笔记-快速入门

大家在日常开发中应该能发现&#xff0c;单表的CRUD功能代码重复度很高&#xff0c;也没有什么难度。而这部分代码量往往比较大&#xff0c;开发起来比较费时。 因此&#xff0c;目前企业中都会使用一些组件来简化或省略单表的CRUD开发工作。目前在国内使用较多的一个组件就是…

Maven jar 包下载失败问题处理

Maven jar 包下载失败问题处理 1.配置好国内的Maven源2.重新下载3. 其他问题 1.配置好国内的Maven源 打开⾃⼰的 Idea 检测 Maven 的配置是否正确&#xff0c;正确的配置如下图所示&#xff1a; 检查项⼀共有两个&#xff1a; 确认右边的两个勾已经选中&#xff0c;如果没有请…

2.5学习

misc buuctf-假如给我三天光明 下载附件后得到了一个压缩包和一个图片&#xff0c;压缩包为加密压缩包&#xff0c;需要解出密码&#xff0c;然后注意到这个图片并非简单的一个封面&#xff0c;在下方还有诸多点&#xff0c;有黑有灰。经过搜索&#xff0c;发现这是盲文通过与…

java进阶1——JVM

java进阶——JVM 1、JVM概述 作用 Java 虚拟机就是二进制字节码的运行环境&#xff0c;负责装载字节码到其内部&#xff0c;解释/编译为对 应平台上的机器码指令行&#xff0c;每一条 java 指令&#xff0c;java 虚拟机中都有详细定义&#xff0c;如怎么取操 作数&#xff0c…