书籍在线阅读链接:https://gpp.tkchu.me/design-patterns-revisited.html
书籍设计模式的unity实现的链接:https://zhuanlan.zhihu.com/p/39707078 很好的文章,简单的实现了该书的大部分设计模式
1,观察者模式
随便打开电脑中的一个应用,很有可能它就使用了MVC架构, 而究其根本,是因为观察者模式。
观察者模式应用广泛,Java甚至将其放到了核心库之中(java.util.Observer),而C#直接将其嵌入了语法(event关键字)。 难以置信的是,如此直观的东西是无数程序和应用框架交流的主心骨。
观察者模式是同步的。 被观察者直接调用了观察者,这意味着直到所有观察者的通知方法返回后, 被观察者才会继续自己的工作。观察者会阻塞被观察者的运行。
如果观察者列表存在触发的顺序关系,这意味着这两个观察者有一些微妙的耦合,最终会害了你。
但是如果耦合发生在观察者列表中,想要知道哪个观察者被通知到了,唯一的办法是看看哪个观察者在列表中,而且处于运行中。 你得理清它的命令式,动态行为而非理清程序的静态交流结构。
如果为了理解程序的一部分,两个交流的模块都需要考虑, 那就不要使用观察者模式,使用其他更加显式的东西。
观察者模式是一个让这些不相关的代码块互相交流(比如:成就系统,任何完全不相干的事物都可以达成成就),而不必打包成更大的块的好方法。 这在专注于一个特性或层面的单一代码块内不会太有用。
如果设计今日的观察者模式,我会让它基于函数,而不是基于类。 哪怕是在C++中,我倾向于让你注册一个成员函数指针作为观察者,而不是Observer接口的实例。实现一整套接口只是为了接受一个通知不再符合今日的美学了。
个人感觉是:只要达到类似于观察者的通信形式,无论哪种写法都是可以的。
实现 https://blog.youkuaiyun.com/tran119/article/details/81166636 unity 消息发送机制
2,单例模式
就一句话:只提供一个实例。有2种情况:
1,做为其他类的实例的管理类。一般一个类比如:怪物类,会创建多个实例,这个时候使用一个单例类的一个实例来管理所有的怪物,完成创建,保存这些实例。常见的情况是,一个单例类里面有多个不同的单例类,多个不同的单例类各自管理某种类型的多个实例对象,而这些实例对象各自有自己的属性行为,自行管理自身,或者依靠公用的系统来管理行为,比如:计时器,事件管理等。所以当我们看到某个类是单例时,就应该想到该类是用来控制某一类型的多个实例。
2,异步操作,比如:一个实例删除了某个文件,但另一个实例又去取该文件。
3,状态模式
使用一个枚举列出所有的状态(比如:idle,jump,Attack,jumpAttack,down),使用另一个枚举列出所有的行为(比如:按下空格键,J键)。一个人物一个时间只能存在一种状态,从一种状态只能变成另一种状态,比如:人在jump时,他的下一个状态只能是down或者jumpAttck,不会同时down和jumpAttack。虽然看起来人物在跳跃攻击时也在下落,但是其实是跳跃攻击就包含了下落。
使用2个switch,一个处理状态切换,一个处理行为,并且同时执行相应的函数。这样做的好处是相互之间没有任何关系。如下:
假如按下J键和K键都是攻击
public void OnChangeState()
{
//状态转换
switch (当前行为)
{
case 按下空格键:
当前状态 = jump;
break;
case 按下J键:
case 按下K键:
if(当前状态 = jump)
当前状态 = jumpAttack;
else
当前状态 = Attack;
break;
default:
break;
}
//状态行为
switch (当前状态)
{
case jump:
执行jump相关函数
break;
case jumpAttack:
执行jumpAttack相关函数
break;
default:
break;
}
}
4,命令模式
个人感觉,不看到真正使用过得代码,根本不能理解为什么是这样的,尽管作者的例子都能看懂。
将函数作为数据,用来传递,存储,重复使用。
--inputHandler维护了所有继承了Command的子类的对象,通过handleInput拿到当前需要的子类对象,然后传递一个当前需要执行当前行为的人物作为参数。
Command* command = inputHandler.handleInput();
if (command)
{
command->execute(actor);
}