C#核心(14)七大原则

[复制链接]
发表于 2025-12-19 21:17:22 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
前言

着实在面向对象操持里,步伐猿们相互约定好一些原则,即七大原则。
面向对象的七大原则是一组引导软件操持的原则,旨在资助开辟职员实现松耦合、可维护和可扩展的软件体系。这些原则的操持过程和发展汗青可以追溯到20世纪80年代。

  •         单一职责原则(Single Responsibility Principle):这个原则最早由罗伯特·C·马丁(Robert C. Martin)提出,并在他的《敏捷软件开辟:原则、模式和实践》一书中具体论述。该原则指出,一个类应该只有一个引起厘革的缘故原由,即一个类应该只负责一项职责。如许可以实现类的高内聚性和低耦合性。
  •         开放关闭闭原则(Open-Closed Principle):开放封闭原则由伯特兰·梅耶(Bertrand Meyer)提出,他在他的《面向对象软件构造》一书中具体论述了该原则。该原则指出,一个软件实体(类、模块、函数等)应该对扩睁开放,对修改封闭。这意味着当需求改变时,应该通过扩显现有实体而不是修改已有代码
  •         里氏更换原则(Liskov Substitution Principle):里氏更换原则由芭芭拉·利斯科夫(Barbara Liskov)提出,并在她的论文《数据抽象和条理范例》中具体论述。该原则指出,子类对象应该可以大概更换全部使用基类对象的地方,而不会产生错误或违背体系的举动。这可以包管继续关系的正确性。
  •         依赖倒置原则(Dependency Inversion Principle):依赖倒置原则由罗伯特·C·马丁提出,并在他的《敏捷软件开辟:原则、模式和实践》一书中具体论述。该原则指出,高层模块不应该依赖于低层模块,它们应该依赖于抽象。如许可以实现模块之间的松耦合。
  •         接口隔离原则(Interface Segregation Principle):接口隔离原则由罗伯特·C·马丁提出,并在他的《敏捷软件开辟:原则、模式和实践》一书中具体论述。该原则指出,客户端不应该依赖于它不必要的接口。一个类只应该依赖于它所使用的接口,制止了不须要的依赖。
  •         迪米特法则(Law of Demeter)(也叫最少知识原则):迪米特法则由伊恩·霍洛维茨(Ian Holland)和巴斯卡尔·勒格兰(Pascal Leroux)提出,并在他们的论文《迪米特法则对面向对象操持的影响》中具体论述。该原则指出,一个对象应该对其他对象保持最少的相识,只与直接的朋侪交换。如许可以淘汰对象之间的耦合。
  •         合成复用原则(Composite Reuse Principle):合成复用原则由伊恩·霍洛维茨和巴斯卡尔·勒格兰提出,并在他们的论文《迪米特法则对面向对象操持的影响》中具体论述。该原则指出,只管使用对象组合,而不是继续来实当代码的复用。如许可以使体系更加机动和可扩展。
随着面向对象编程的鼓起和软件开辟的需求不停演变,它们得到了广泛的应用和发展。这些原则的目的是进步软件体系的可维护性、可扩展性和可重用性,使软件的开辟过程更加机动和高效,而本日我们也将具体讲讲七大原则,渴望能在日后的编程对你有所资助。
简述


  •         单一职责原则(Single Responsibility Principle,SRP):一个类应该只有一个厘革的缘故原由,即每个类应该只负责一项功能
  •         开放-关闭原则(Open/Closed Principle,OCP):软件实体(类、模块、函数等)应该对扩睁开放,对修改关闭。也就是说,可以通过扩显现有代码而不是修改它来实现新功能
  •         里氏更换原则(Liskov Substitution Principle,LSP):子类对象应该可以大概更换父类对象而不影响步伐的正确性,确保子类的举动符合父类的预期。
  •         接口隔离原则(Interface Segregation Principle,ISP):不应欺压客户端依赖于它们不使用的接口。应该将大的接口拆分成多个小接口,以便于实现和使用。
  •         依赖反转原则(Dependency Inversion Principle,DIP):高层模块不应依赖于低层模块,二者都应依赖于抽象(接口或抽象类),而不应依赖于具体实现。
  •         合成复用原则(Composite Reuse Principle,CRP):只管使用对象的组合而不是继续来实当代码复用。组合关系比继续关系更机动。
  •         最少知识原则(Least Knowledge Principle,LKP):一个对象应该对其他对象有最少的相识。淘汰对象之间的耦合,通过公共接口举行交互。
大概你单看笔墨很多都还看不懂,有些东西乃至必要你学习了之后的东西再返来看,如果你是序次查察博主的博文的话,发起只看里氏更换原则。
单一职责原则 

根本概念

夸大一个类应该只有一个单一的责任,即一个类应该仅仅负责一个功能或任务。
重点


  • 单一性:每个类保持单一功能,简化类的接口。
  • 职责分别:明确界定类的职责,制止交织影响。
  • 易维护性:变动一个责任时只需修改干系类,低落了风险。
作用


  • 进步可读性和可明确性:清晰的职责使得代码更易于阅读和明确。
  • 提升可维护性:淘汰了因改动引入的bug,由于每个类变动都与其单一的功能干系。
  • 加强可重用性:聚焦于单一功能的类可以更容易地被重用于其他项目中。
示例

这个示例是着实也是各人在日后unity的操持中也常常使用的模式,固然,gamemanager用来具体干什么,就要视环境而定了。
  1. using System;
  2. using System.Collections.Generic;
  3. // 游戏管理类,负责管理游戏逻辑
  4. class GameManager
  5. {
  6.     private Player player;
  7.     private List<Enemy> enemies;
  8.     public GameManager()
  9.     {
  10.         player = new Player();
  11.         enemies = new List<Enemy>();
  12.         InitializeEnemies();
  13.     }
  14.     // 初始化敌人
  15.     private void InitializeEnemies()
  16.     {
  17.         enemies.Add(new Enemy("Enemy 1"));
  18.         enemies.Add(new Enemy("Enemy 2"));
  19.         enemies.Add(new Enemy("Enemy 3"));
  20.     }
  21.     // 游戏主循环
  22.     public void Run()
  23.     {
  24.         while (true)
  25.         {
  26.             player.Update();
  27.             foreach (Enemy enemy in enemies)
  28.             {
  29.                 enemy.Update();
  30.             }
  31.             if (player.IsCollidingWithEnemy(enemies))
  32.             {
  33.                 Console.WriteLine("Player collided with an enemy");
  34.                 break;
  35.             }
  36.         }
  37.     }
  38. }
  39. // 玩家类,负责玩家相关逻辑
  40. class Player
  41. {
  42.     public void Update()
  43.     {
  44.         Console.WriteLine("Player is updating");
  45.     }
  46.     public bool IsCollidingWithEnemy(List<Enemy> enemies)
  47.     {
  48.         // 检测玩家是否与敌人发生碰撞
  49.         foreach (Enemy enemy in enemies)
  50.         {
  51.             if (enemy.Position == this.Position)
  52.             {
  53.                 return true;
  54.             }
  55.         }
  56.         return false;
  57.     }
  58.     // 玩家的其他属性和方法...
  59. }
  60. // 敌人类,负责敌人相关逻辑
  61. class Enemy
  62. {
  63.     public string Name { get; private set; }
  64.     public int Position { get; private set; }
  65.     public Enemy(string name)
  66.     {
  67.         Name = name;
  68.         Position = 0;
  69.     }
  70.     public void Update()
  71.     {
  72.         Console.WriteLine($"{Name} is updating");
  73.         Position++;
  74.     }
  75.     // 敌人的其他属性和方法...
  76. }
  77. class Program
  78. {
  79.     static void Main(string[] args)
  80.     {
  81.         GameManager game = new GameManager();
  82.         game.Run();
  83.     }
  84. }
复制代码
开放-关闭原则

根本概念

开放-关闭原则是对象操持中的一种原则,其核心头脑是“软件实体(类、模块、函数等)应该对扩睁开放,对修改封闭。
重点


  • 开放性:答应在不改变现有代码的环境下添加新功能。
  • 封闭性:现有的代码在功能上不会被修改,应该能安全地被使用。
  • 通过继续和接口等机制支持机动的扩展。
作用


  • 加强软件的可维护性和可扩展性。
  • 淘汰代码修改带来的风险,低落不测引入bug的大概性。
  • 促进模块化操持,使得体系可以方便地举行部件更换或升级。
示例

在Main方法中,我们创建了一个包罗一个兵士和一个法师脚色的游戏场景对象,并调用了RunGame()方法。由于Character类是开放的,我们可以随时添加新的脚色类而不必要修改GameScene类的代码,同时GameScene类的代码是关闭的,不必要对新的脚色类举行修改,这就是所谓的开放关闭原则。
  1. using System;
  2. // 游戏角色基类
  3. abstract class Character
  4. {
  5.     public abstract void Attack();
  6.     //可以在这里添加方法
  7. }
  8. // 战士角色
  9. class Warrior : Character
  10. {
  11.     public override void Attack()
  12.     {
  13.         Console.WriteLine("战士发起了一次普通攻击!");
  14.     }
  15. }
  16. // 法师角色,你还可以写一个牧师角色(相当于开放的)
  17. class Mage : Character
  18. {
  19.     public override void Attack()
  20.     {
  21.         Console.WriteLine("法师施放了一次火球术!");
  22.     }
  23. }
  24. // 游戏场景类(相当于关闭了,不用管里面的)
  25. class GameScene
  26. {
  27.     private Character[] characters;
  28.     public GameScene(Character[] characters)
  29.     {
  30.         this.characters = characters;
  31.     }
  32.     public void RunGame()
  33.     {
  34.         foreach (Character character in characters)
  35.         {
  36.             character.Attack();
  37.         }
  38.     }
  39. }
  40. class Program
  41. {
  42.     static void Main(string[] args)
  43.     {
  44.         Character[] characters = { new Warrior(), new Mage() };
  45.         GameScene gameScene = new GameScene(characters);
  46.         gameScene.RunGame();
  47.     }
  48. }
复制代码
里氏更换原则

根本概念

任何父类出现的地方,子类都可以更换
重点

语法体现——父类容器装子类对象,由于子类对象包罗了父类的全部内容
作用

示例

简单写一个,我就不多表明了,就是简单的父类装子类。
  1. using System;
  2. public class Shape
  3. {
  4.     public virtual double CalculateArea()
  5.     {
  6.         return 0;
  7.     }
  8. }
  9. public class Rectangle : Shape
  10. {
  11.     public double Width { get; set; }
  12.     public double Height { get; set; }
  13.     public override double CalculateArea()
  14.     {
  15.         return Width * Height;
  16.     }
  17. }
  18. public class Square : Shape
  19. {
  20.     public double SideLength { get; set; }
  21.     public override double CalculateArea()
  22.     {
  23.         return SideLength * SideLength;
  24.     }
  25. }
  26. public class Program
  27. {
  28.     public static void Main(string[] args)
  29.     {
  30.         Shape shape1 = new Rectangle { Width = 5, Height = 10 };
  31.         Shape shape2 = new Square { SideLength = 5 };
  32.         Console.WriteLine("Rectangle Area: " + shape1.CalculateArea());
  33.         Console.WriteLine("Square Area: " + shape2.CalculateArea());
  34.     }
  35. }
复制代码
接口隔离原则

根本概念

核心头脑是“客户端不应该被迫依赖于它不使用的接口。” 简而言之,就是每个接口应该只包罗客户端所需的方法,制止将多个不干系的方法聚合在一个接口中。
重点


  • 细化接口:将大接口分拆为多个小接口,使得实现这些接口的类更为专注。
  • 低落耦合度:使得类与接口的依赖关系更为正确,减小了体系之间的耦合,加强了机动性。
  • 进步可维护性:低落了不须要的方法对实现类的影响,修改接口时影响范围更小。
作用


  • 加强体系的模块化,易于明确和维护。
  • 进步代码的复用性,使差异的类可以大概更机动地选择必要实现的接口。
  • 低落修改某个接口时,导致其他代码粉碎的风险。
示例

直接看例子,这个规范光靠说的话也很简单,就是不能把太多功能耦合到一个东西身上,打个比方,有些gamejam的顶级步伐猿能把武器,道具这些全写到人物内里去,你可以从本身角度简单评价一下这个代码维护起来有多么逆天。
  1. using System;
  2. // 定义不同接口:播放音频和播放视频分开,当然实际开发不一定这样分,但是你要知道为什么要这样规定
  3. interface IPlayer
  4. {
  5.     void Play();
  6. }
  7. interface IRecord
  8. {
  9.     void Record();
  10. }
  11. // 实现接口
  12. class VideoPlayer : IPlayer
  13. {
  14.     public void Play()
  15.     {
  16.         Console.WriteLine("开始播放视频");
  17.     }
  18. }
  19. class AudioPlayer : IPlayer, IRecord
  20. {
  21.     public void Play()
  22.     {
  23.         Console.WriteLine("开始播放音频");
  24.     }
  25.     public void Record()
  26.     {
  27.         Console.WriteLine("开始录音");
  28.     }
  29. }
  30. class Game
  31. {
  32.     private IPlayer player;
  33.     public Game(IPlayer player)
  34.     {
  35.         this.player = player;
  36.     }
  37.     public void Start()
  38.     {
  39.         player.Play();
  40.     }
  41. }
  42. class Program
  43. {
  44.     static void Main(string[] args)
  45.     {
  46.         IPlayer videoPlayer = new VideoPlayer();
  47.         IPlayer audioPlayer = new AudioPlayer();
  48.         Game videoGame = new Game(videoPlayer);
  49.         videoGame.Start(); // 输出:开始播放视频
  50.         Game audioGame = new Game(audioPlayer);
  51.         audioGame.Start(); // 输出:开始播放音频
  52.     }
  53. }
复制代码
依赖反转原则

根本概念

这个的重要头脑是“高层模块不应该依赖低层模块,二者都应该依赖抽象;抽象不应该依赖于细节,细节应该依赖于抽象。”说人话,依赖于抽象(接口或抽象类)而不是具体实现,如许可以淘汰模块之间的耦合。
重点


  • 高层模块:指的是完成业务逻辑等高级功能的部分。
  • 低层模块:指的是具体的实现细节,比方数据访问或硬件控制。
  • 抽象:通常是一个接口或抽象类,用于界说高层模块和低层模块之间的交互。
作用


  • 进步体系的机动性和可扩展性,方便更换实现。
  • 淘汰模块之间的耦合,使得更改低层实现时不影响高层逻辑。
  • 进步代码的可测试性,通过依赖注入等方式简化单元测试。
示例 

示例中,我们界说了一个接口 IWeapon,以及两个实现类 Sword 和 Bow。然后,在 Player 类中通过构造函数注入 IWeapon 接口的实例,以实现依赖反转原则。如许,我们可以根据必要选择差异的武器,而不必要修改 Player 类的代码。
在 Game 类的 Main 方法中,我们创建了一个 Player 实例,分别使用剑和弓箭举行攻击。如许,我们可以机动地为脚色选择差异的武器,而不必要修改 Game 类的代码。
  1. using System;
  2. // 定义接口
  3. public interface IWeapon
  4. {
  5.     void Attack();
  6. }
  7. // 定义实现类
  8. public class Sword : IWeapon
  9. {
  10.     public void Attack()
  11.     {
  12.         Console.WriteLine("使用剑攻击");
  13.     }
  14. }
  15. public class Bow : IWeapon
  16. {
  17.     public void Attack()
  18.     {
  19.         Console.WriteLine("使用弓箭攻击");
  20.     }
  21. }
  22. // 定义高层模块
  23. public class Player
  24. {
  25.     private IWeapon weapon;
  26.     // 通过构造函数注入依赖
  27.     public Player(IWeapon weapon)
  28.     {
  29.         this.weapon = weapon;
  30.     }
  31.     //避免了你在这里面写一堆道具和武器的方法
  32.     public void Attack()
  33.     {
  34.         weapon.Attack();
  35.     }
  36. }
  37. // 示例程序
  38. public class Game
  39. {
  40.     public static void Main(string[] args)
  41.     {
  42.         IWeapon sword = new Sword();
  43.         Player player1 = new Player(sword);
  44.         player1.Attack();
  45.         IWeapon bow = new Bow();
  46.         Player player2 = new Player(bow);
  47.         player2.Attack();
  48.     }
  49. }
复制代码
实用复用原则

根本概念

大概意思是“你不会必要它”。这个原则夸大在软件开辟中,开辟者不应该添加过多的功能或代码,只应当实现当前需求所需的功能,制止为了未来大概必要的功能而太过操持。
重点


  • 制止太过操持:只开辟当前需求所需的功能,制止思量和实现未来大概不须要的功能。
  • 简化代码:淘汰无谓的复杂性,让代码保持简便和清晰。
  • 进步维护性:随着代码变得复杂,维护的资本会增长,原则资助保持代码的可维护性。
作用


  • 低落项目的复杂度:代码更加简单,易于明确和维护。
  • 进步开辟服从:制止不须要的功能开辟,从而节流时间和资源。
  • 低落堕落概率:淘汰不须要的逻辑和功能可以低落 bug 的数量,进步体系稳固性。
示例 

没有示例,想要告诉你的更多是你要记取,不要多此一举
最少知识原则

根本概念

最少知识原则是面向对象操持中的一项原则,夸大一个对象应当对其他对象有尽大概少的相识。说人话,一个对象应该只与直接的朋侪(互助对象)举行交互,而不应该去相识其他对象之间的复杂关系。
重点


  • 直接交互:对象只应与直接干系的对象举行通讯,制止“连锁调用”。
  • 封装性:通过淘汰对象间的知识,加强封装性,使对象能独立厘革。
  • 低落耦合:淘汰模块之间的依赖,有助于体系的维护和扩展。
作用


  • 进步可维护性:体系的修改和维护更容易,由于对象之间的依赖关系被淘汰。
  • 加强可读性:代码更容易明确,淘汰了对象之间复杂的交互模式。
  • 促进独立性:使得各个模块之间能独立发展,淘汰了相互影响的风险。
示例 

错误树模:假设我们有一个体系,此中 Order 类依赖于 Customer 和 Address 类
  1. public class Address  
  2. {  
  3.     public string Street { get; set; }  
  4.     public string City { get; set; }  
  5. }  
  6. public class Customer  
  7. {  
  8.     public Address Address { get; set; }  
  9. }  
  10. public class Order  
  11. {  
  12.     public Customer Customer { get; set; }  
  13.     public void PrintShippingAddress()  
  14.     {  
  15.         // 连锁调用,不符合最少知识原则  
  16.         Console.WriteLine($"Shipping to: {Customer.Address.Street}, {Customer.Address.City}");  
  17.     }  
  18. }
复制代码
改进后:
  1. public class Address  
  2. {  
  3.     public string Street { get; set; }  
  4.     public string City { get; set; }  
  5.     public string GetFullAddress()  
  6.     {  
  7.         return $"{Street}, {City}";  
  8.     }  
  9. }  
  10. public class Customer  
  11. {  
  12.     public Address Address { get; set; }  
  13.     public string GetShippingAddress()  
  14.     {  
  15.         return Address.GetFullAddress();  
  16.     }  
  17. }  
  18. public class Order  
  19. {  
  20.     public Customer Customer { get; set; }  
  21.     public void PrintShippingAddress()  
  22.     {  
  23.         // 只与 Customer 交互,符合最少知识原则  
  24.         Console.WriteLine($"Shipping to: {Customer.GetShippingAddress()}");  
  25.     }  
  26. }
复制代码
我想这个示例能让你明确这是什么个环境
总结

七大原则本身着实是各人不停探索后发现的约定,着实你可以不如许写步伐,固然你在碰到长期项目的时间一定会碰到很多标题,规范的代码有主意你更好地举行长线开辟。
大概博主对着七大原则的明确也有一些误区,欢迎品评指正。
照旧那句话,学习路上,实事求是。
请等待我的下一篇博客!
我来自佑梦游戏开辟,感谢你的关注和收藏!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!qidao123.com:ToB企服之家,中国第一个企服评测及软件市场,开放入驻,技术点评得现金
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表