OpenClaw自动生成1
测试OpenClaw生成博客
测试OpenClaw生成博客
依赖倒置原则(Dependence Inversion Principle)是程序要依赖于抽象接口,不要依赖于具体实现。简单的说就是要求对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模块间的耦合。
总结:依赖倒置原则
当在 Unity 设计底层模块时,上层模块调用的东西其实就只是一些暴露出来的方法,当底层改动的时候上层也需要改动,这就形成了高层次模块对低层次模块的依赖。这时候可以抽象出来这些需要暴露的方法,即使用接口抽象出来,使得底层依赖了抽象的接口,高层也依赖了抽象的接口,从而使得设计更加清爽。
浅谈Unity开发中的分层设计 中也使用了接口抽象的方式,不过是在底层之间的相互依赖中使用了接口,对于上层还是通过暴露公共方法的方式,加了个 模块管理器,来取得具体模块或者具体实现的接口。

将类的功能层次结构和实现层次结构相分离,使二者能够独立地变化,并在两者之间搭建桥梁,实现桥接。它是一种对象结构型模式,又称为柄体(Handle and Body)模式或接口(Interfce)模式。
意图:在一个软件系统的抽象化和实现化之间使用关联关系(组合或者聚合关系)而不是继承关系,从而使两者可以相对独立地变化。
桥接模式主要包含以下几个角色
现要画一个不同颜色不同形状组合的圆,把抽象化和实现分离开来使其能独立地变化
抽象类:
1 | public abstract class Shape |
扩充抽象类
1 | public class Circle : Shape |
实现类的接口:
1 | public interface Color |
具体实现类:
1 | public class Red : Color |
画出不同颜色不同形状的圆:
1 | public class Draw |
享元模式(Flyweight),运用共享技术有效地支持大量细粒度的对象。UML结构图如下:
Flyweight是抽象享元角色。它是产品的抽象类,同时定义出对象的外部状态和内部状态的接口或实现;ConcreteFlyweight是具体享元角色,是具体的产品类,实现抽象角色定义的业务;
UnsharedConcreteFlyweight是不可共享的享元角色,一般不会出现在享元工厂中;
FlyweightFactory是享元工厂,它用于构造一个池容器,同时提供从池中获得对象的方法。
享元享元,共享细粒度的单元。那么什么是细粒度的单元呢?如果用乐高积木作比喻,那么一个积木人可以称为一个完整的对象。如果我们把积木人拆开,可以进一步得到头、身躯,腿三个部分。而这些部分,相比于完整的积木人而言,它们三个就是细粒度的单元。
那么为什么要把一个完整的对象区分内外部呢?这岂不是增加了代码的复杂度?好,我们暂时搁置,接下来思考这样一个问题,如果我们要创造 10 个积木人,用程序怎么表示呢?
我们先创建一个积木人的类,如下:
1 | public class LegoMan |
接着我们开始创造积木人,先采用直接 new 的方式:
1 | public class Example { |
现在我们得到了 10 个积木人,接下来我们对积木人作出一些限制,我们现在需要 10 个士兵积木人,由于士兵的制服统一,那么这一百个积木人的下半身是完全一样的,也就是说除了 Head,积木人的 Torso 和 Leg 都是一样的。现在我们继续创建十个士兵积木人。好吧,和上面的例子一样,只是传入的后两个参数均一致。
1 | LegoMan manN = new LegoMan("headN", "torsoStandard", "legStandard") |
接下来,我们思考这样一个问题,如果需要 1000 个士兵积木人呢?如果采用一般的方式,需要创建 1000 个实例对象,但是这 1000 个对象都有着共同的部分,就是它们的 Torso 和 Leg。那我们可不可以把共同的部分抽取出来呢?当然可以,现在我们把 Torso 和 Leg 整合为一个 Body 类,如下:
1 | public class Body |
既然 Body 被提取出来了,那么 LegoMan 这个类也要被重写了,如下:
1 | public class LegoMan |
现在我们再来创建 1000 个积木人士兵的话,应该是这样:
1 | public class Example { |
发现了吗?现在虽然也是1000个 LegoMan 的实例,但是却只有一个 Body,也就是说,1000个积木人士兵 的 Head,共享了一个 Body。听起来很疯狂,九头蛇也才九头,一千个头的怪物得多可怕!?哈哈,虽然积木人的玩具不可能这么拼,但是程序里,这种共享机制是可行的。Body 就是享元模式中的内部状态,一个重复度很高的细粒度单元。而 Head 则对应外部状态,会随着需求发生变化。这么分离的好处也很明显,就是大大减少了总数据量。如果不分离内外部,创建 1000 个积木人士兵的成本就是1000个 Head 和1000个 Body,而采用分离策略后,就只需要1000个 Head 外加1个 Body了。当随着创建对象数量级的增大,这种策略带来的好处会越来越明显。
理解了分离内外部的原因后,下面简单实现一下享元模式
通过最上面的 UML 图可以看出,Flyweight 被分为两部分,ConcreteFlyweight(共享的内部)和UnsharedConcreteFlyweight(不可共享的外部)。所以 Flyweight 最好被做成接口,或者抽象类,这里用抽象类实现,如下:
1 | public abstract class Flyweight |
1 | public class ConcreteFlyweight : Flyweight |
1 | public class UnsharedConcreteFlyweight : Flyweight |
既然是处理大量数据,那免不了用一个对象池来进行管理,如下:
1 | public class FlyweightFactory |
1 | public class Client { |
打印结果如下:
新创建 one
处理共享数据 one
新创建 two
处理共享数据 two
从池中取出 one
处理共享数据 one
非共享的 one
处理非共享数据 one
参考博客:
https://www.cnblogs.com/adamjwh/p/9070107.html
https://blog.csdn.net/justloveyou_/article/details/55045638
命令模式在GoF中的定义是:
将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化; 对请求排队或记录请求日志,以及支持可撤销的操作。
命令模式是一种回调的面向对象实现。
游戏设计模式里把它精简为:
命令是具现化的方法调用。
两种术语都意味着将概念变成数据一个对象可以存储在变量中,传给函数。
所以称命令模式为“具现化方法调用”,意思是方法调用被存储在对象中。
类似C#里的回调
把一个对象传递到方法中,让方法内部解析。
下面是一个C#版本的角色控制,传入一个角色,就能调用对应的各种行动。
1 | using UnityEngine; |
实现了最简单的有限状态机
1 | public class FSM : MonoBehaviour |
使用Unity里的方法
1 | public abstract class ScriptSingleton<T> : MonoBehaviour where T : ScriptSingleton<T> |
通过反射实现的单例
1 | public abstract class Singleton<T> where T : Singleton<T> |
模板测试一般发生在深度测试前,在片段着色器处理完一个片段后执行。和深度测试一样也会丢弃片元。模板测试是根据一个缓冲来进行的,它叫做模板缓冲(Stencil Buffer)
一个模板缓冲中,(通常)每个模板值(Stencil Value)是8位的。所以每个像素/片段一共能有256种不同的模板值。我们可以将这些模板值设置为我们想要的值,然后当某一个片段有某一个模板值的时候,我们就可以选择丢弃或是保留这个片段了。
模板缓冲操作允许我们在渲染片段时将模板缓冲设定为一个特定的值。通过在渲染时修改模板缓冲的内容,我们写入了模板缓冲。在同一个(或者接下来的)渲染迭代中,我们可以读取这些值,来决定丢弃还是保留某个片段。使用模板缓冲的时候你可以尽情发挥,但大体的步骤如下:
所以,通过使用模板缓冲,我们可以根据场景中已绘制的其它物体的片段,来决定是否丢弃特定的片段。
一般来说,stencil完整的语法如下
1 | stencil |
我们可以用模板缓冲来实现一个物体轮廓,步骤如下:
这个过程将每个物体的片段的模板缓冲设置为1,当我们想要绘制边框的时候,我们主要绘制放大版本的物体中模板测试通过的部分,也就是物体的边框的位置。我们主要使用模板缓冲丢弃了放大版本中属于原物体片段的部分。