Unity【话大】设计模式之面向对象七大原则

简介: 首先放出早先写的面向对象七大原则,以前不了解的同学建议先大概看一遍~有说的不正确或者不准确的地方欢迎留言指正有什么有趣的写作技巧或者想法欢迎大家给我留言,大家的帮助是我写下去最有效的动力下面笔者跟大家聊一聊每一条原则到底是个什么东东[1]单一职责原则(Single Responsibility Principle)见名知意,这个条职责的潜台词的就是,专注做一个事、专注做一个事、专注做一个事,重要的事说三遍。

首先放出早先写的面向对象七大原则,以前不了解的同学建议先大概看一遍~



有说的不正确或者不准确的地方欢迎留言指正


有什么有趣的写作技巧或者想法欢迎大家给我留言,大家的帮助是我写下去最有效的动力



下面笔者跟大家聊一聊每一条原则到底是个什么东东



[1]

单一职责原则(Single Responsibility Principle)

见名知意,这个条职责的潜台词的就是,专注做一个事、专注做一个事、专注做一个事,重要的事说三遍。别的事情我都不管,我只负责我的事情,专注干好自己的东西。

那单一职责用在程序中有什么好处呢?

  • 提高可读性,想想10个功能放在一个类里面写方便阅读还是分10个类方便阅读?
  • 出现BUG时可以缩小出错的范围,更好的定位,哪个功能出错找哪个功能,早日和BUG说ByeBye~
  • 修改逻辑时避免造成其他功能模块错误,例如折扣数值更改0.8,你不小心把极品装备爆率改成0.8,那你就等死吧


[2]

里氏替换原则(Liskov Substitution Principle)

通俗的讲就是老子不在可以用儿子顶替,具体这条原则怎么个好法请看下面的示例

基础代码
public abstract class  Phone
{
    public abstract void Call();
}
 interface Android{ }
 interface IOS{ }
public class OnePlus : Phone, Android
{
    public override void Call()
    {
        Debug.Log($"{nameof(OnePlus)}进行通话。。。。。");
    }
}

public class Pixel : Phone, Android
{
    public override void Call()
    {
        Debug.Log($"{nameof(Pixel)}进行通话。。。。。");
    }
}
public class XiaoMi : Phone, Android
{
    public override void Call()
    {
        Debug.Log($"{nameof(XiaoMi)}进行通话。。。。。");
    }
}

public class Apple : Phone, IOS
{
    public override void Call()
    {
        Debug.Log($"{nameof(Apple)}进行通话。。。。。");
    }
}

不使用里氏替换,调用call函数需要为每个类型的手机写一个函数

    public void WantToCall_0(OnePlus phone)
    {
        phone.Call();
    }

    public void WantToCall_1(Pixel phone)
    {
        phone.Call();
    }

    public void WantToCall_2(XiaoMi phone)
    {
        phone.Call();
    }

    public void WantToCall_3(Apple phone)
    {
        phone.Call();
    }

使用里氏替换,只需要一个函数全部搞定,在后面的【桥接模式】会广泛用到的

    public void WantToCall_4(Phone phone)
    {
        phone.Call();
    }


[3]

依赖倒置原则(Dependence Inversion Principle)

定义:高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。 依赖倒置原则的核心思想是面向接口编程。

下面我们先解释接个名词,什么是高层模块,什么是低层模块?什么是细节,什么是抽象?

在项目中我们经常会有一些数学函数库,或者工具类(Log日志工具),这些封装好的工具会被我们业务逻辑模块经常调用,那么这些工具函数库就是低层模块,业务逻辑模块就是高层模块。

细节的意思就是具体的实现,例如上面里氏替换中打电话的例子,在不使用里氏替换的时候需要定义4种打电话函数,这就是依赖细节,其中的细节就是“OnePlus ”、“Pixel ”、“XiaoMi”、“Apple ”,反之抽象就是Phone

下面笔者就举一个例子来说明,示例是这样的,华硕和微型都可使用不同型号的显卡,反之不同型号的显卡也可以使用在不同品牌的主板上。利用依赖倒置原则,这种规则的实现变得很简单也很灵活~

基础代码

//显卡
public interface IGraphicsCard
{
    void BeginWork(IMainboard mainboard);
}
//主板
public interface IMainboard
{
    void GetElectricity();
    void DrawPicture(IGraphicsCard graphicsCard);
}


public class NVIDIA_2018Ti : IGraphicsCard
{
    public NVIDIA_2018Ti(IMainboard mainboard)
    {
        BeginWork(mainboard);
    }
    public void BeginWork(IMainboard mainboard)
    {
        mainboard.GetElectricity();
        Debug.Log($"NVIDIA_2018Ti获取{mainboard.GetType()}电量后开始工作");
    }
}
public class NVIDIA_2018 : IGraphicsCard
{
    public NVIDIA_2018(IMainboard mainboard)
    {
        BeginWork(mainboard);
    }
    public void BeginWork(IMainboard mainboard)
    {
        mainboard.GetElectricity();
        Debug.Log($"NVIDIA_2018获取{mainboard.GetType()}电量后开始工作");
    }
}

//华硕主板
public class Asus : IMainboard
{
    public void DrawPicture(IGraphicsCard graphicsCard) { }
    public void GetElectricity() { }
}
//微型主板
public class MSI : IMainboard
{
    public void DrawPicture(IGraphicsCard graphicsCard) { }
    public void GetElectricity() { }
}

实现代码,这种2*2种模式的实现非常简单~

    public void DrawPicture()
    {
        IMainboard aSus = new Asus();
        aSus.DrawPicture(new NVIDIA_2018Ti(aSus));
        aSus.DrawPicture(new NVIDIA_2018(aSus));

        IMainboard mSI = new MSI();
        mSI.DrawPicture(new NVIDIA_2018Ti(mSI));
        mSI.DrawPicture(new NVIDIA_2018(mSI));
    }


[4]

接口隔离原则(Interface Segregation Principle)

通俗的讲就是定义的接口尽量按照功能细分,比如打电话功能一个接口,上网一个接口,发短信一个接口,分的够细不仅职能明确,也不会因为使用某种职能必须实现一些没必要的功能。总之通过分散定义多个接口,可以预防外来变更的扩散,提高系统的灵活性和可维护性。

我们可以先参考下微软他们的做法,都是按职能划分,而且划分的很细

img_d7db5e117e78a2f4b97e5b24a3ee54ec.png


[5]

迪米特法则(Law Of Demeter)也叫【最少知识原则】

他想表达的意思是能用 private、protected的就不要用public,不要过多的暴露自己的内容,而且对应类与类之间的关系,尽量越少越好。后面讲到的【门面模式】和【中介者模式】想表达的也是这个意思。

迪米特法则其根本思想,是强调了类之间的松耦合。类之间的耦合越弱,一个处于弱耦合的类被修改,不会对有关系的类造成波及。

在下面的示例中说明的是GameObject扩展Log方法都写在了Object上面,这种情况就违背了迪米特法则。因为其他的类不需要这个Log扩展,这也就破坏了原来的结构,侵入性太强了。如果所有的扩展都是以Object为基准,那么调用函数的时候就会出现数不过来的函数下拉条目~~~~

public static class Exted
{
    public static void CustomerLog_Obj0(this GameObject Obj) { }

    public static void CustomerLog_Obj1(this object Obj) { }
    public static void CustomerLog_Obj2(this object Obj) { }

    public static void CustomerLog_Obj3(this object Obj) { }
    public static void CustomerLog_Obj4(this object Obj) { }
}
img_9a6219d8e2787139fe570debd6b21a33.png


[6]

开闭原则(Open Close Principle)

开放封闭原则主要体现在对扩展开放、对修改封闭,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况.封装变化,是实现开放封闭原则的重要手段,对于经常发生变化的状态,一般将其封装为一个抽象,拒绝滥用抽象,只将经常变化的部分进行抽象。

通俗的讲在功能变动的时候,尽量以增量补丁的形式更改,也就是原来的东西尽量原封不动,继承原来的东西在添加。比如原来的东西作为父类,新的更改在子类里面实现。



[7]

组合/聚合复用原则(Composite/Aggregate Reuse Principle CARP)

引用老版本的话~

因为:其实整个设计模式就是在讲如何类与类之间的组合/聚合。在一个新的对象里面通过关联关系(包括组合关系和聚合关系)使用一些已有的对象,使之成为新对象的一部分,新对象通过委派调用已有对象的方法达到复用其已有功能的目的。也就是,要尽量使用类的合成复用,尽量不要使用继承。
如果为了复用,便使用继承的方式将两个不相干的类联系在一起,违反里氏代换原则,哪是生搬硬套,忽略了继承了缺点。继承复用破坏数据封装性,将基类的实现细节全部暴露给了派生类,基类的内部细节常常对派生类是透明的,白箱复用;虽然简单,但不安全,不能在程序的运行过程中随便改变;基类的实现发生了改变,派生类的实现也不得不改变;从基类继承而来的派生类是静态的,不可能在运行时间内发生改变,因此没有足够的灵活性。
所以:组合/聚合复用原则可以使系统更加灵活,类与类之间的耦合度降低,一个类的变化对其他类造成的影响相对较少,因此一般首选使用组合/聚合来实现复用;其次才考虑继承,在使用继承时,需要严格遵循里氏代换原则,有效使用继承会有助于对问题的理解,降低复杂度,而滥用继承反而会增加系统构建和维护的难度以及系统的复杂度,因此需要慎重使用继承复用。


  1. 单一职责原则脚注结尾

  2. 里氏替换原则脚注结尾

  3. 依赖倒置原则脚注结尾

  4. 接口隔离原则脚注结尾

  5. 迪米特法则脚注结尾

  6. 开闭原则脚注结尾

  7. 组合/聚合复用原则脚注结尾

相关文章
|
18天前
|
设计模式 前端开发 Java
设计模式之六大基本原则
设计模式之六大基本原则
21 0
|
18天前
|
设计模式 算法 架构师
【搞懂设计模式】设计模式与面向对象原则
【搞懂设计模式】设计模式与面向对象原则
15 1
|
18天前
|
设计模式 前端开发 API
写出易维护的代码|React开发的设计模式及原则
本文对React社区里出现过的一些设计模式进行了介绍,并讲解了他们遵循的设计原则。
|
18天前
|
设计模式 数据可视化 关系型数据库
设计之美-揭秘设计模式、原则与UML的魔法
设计模式、设计原则和UML是软件工程设计中的核心要素。设计模式为常见问题提供经验证的解决方案,复用性高且提升开发效率。设计原则指导我们创建灵活、可维护和可扩展的系统,确保代码质量和长期可维护性。UML(统一建模语言)则是一种强大的可视化工具,用于描述、构建和文档化软件系统的结构和行为。它帮助开发者更清晰地理解系统架构和组件间关系。综合应用设计模式、设计原则和UML,能够显著提高软件开发的效率和质量,减少维护成本,为复杂系统的设计和实施提供有力支持。
38 0
设计之美-揭秘设计模式、原则与UML的魔法
|
18天前
|
设计模式 关系型数据库
设计模式的六大原则:理解设计模式的关键思想和应用
设计模式的六大原则:理解设计模式的关键思想和应用
19 2
|
18天前
|
设计模式
【设计模式】1、设计模式七大原则
【设计模式】1、设计模式七大原则
20 0
|
18天前
|
设计模式 Java 编译器
Java 设计模式最佳实践:一、从面向对象到函数式编程
Java 设计模式最佳实践:一、从面向对象到函数式编程
70 0
|
18天前
|
开发框架 Java C#
【Unity逆向】玩游戏遇到的“飞天锁血”是怎么实现的?
【Unity逆向】玩游戏遇到的“飞天锁血”是怎么实现的?
107 0
|
18天前
|
存储 自然语言处理 监控
【Unity 实用工具篇】| 游戏多语言解决方案,官方插件Localization 实现本地化及多种语言切换
Unity的多语言本地化是一个很实用的功能,它可以帮助游戏支持多种语言,让不同语言的玩家都能够更好地体验游戏。 而实现本地化的方案也有很多种,各个方案之间也各有优劣,后面也会对多个方案进行介绍学习。 本文就来介绍一个专门作用于多语言本地化的Unity官方插件:Localization 。 这个插件方便进行游戏的多语言本地化,让游戏支持多种语言,下面就来看看该插件的使用方法吧!
|
18天前
|
定位技术 C# 图形学
Unity和C#游戏编程入门:创建迷宫小球游戏示例
Unity和C#游戏编程入门:创建迷宫小球游戏示例
91 2