项目问题
1 MVC和MVVM的区别
1.1 MVC(Model View Control):
C可以直接引用V和M,而V和M不能直接引用C,而V和M之间则是双黄线,它们俩谁也不能引用谁,你既不能在M里面写V,也不能在V里面写M。
1.1.1 对于View和Controller的交互
举例:比如按钮点击事件,是View来接收的,但是处理这个事件的应该是Controller,所以View把这个事件传递给了Controller。Controller实际上就是靶子
,View只负责传递事件,不负责关心靶子是谁。这是V和C的一种交互方式,叫做target-action。
总结一下,就是主要通过三种方式:action-target
用来负责传递特定的事件;dataSource-protocol
用来通过回调的形式动态通过数据绘制界面;delegate-protocol
提前约定了对一些事件的处理规则,当被规定的事件发生后,就按照协议的规定来进行处理。协议委托可以通过协议方法的参数由V向C传值。比如cell点击事件的协议方法,tableView通过indexPath参数告诉C是哪个cell被点击了。
1.1.2 Model和Controller的交互
M就是数据管理者,你可以理解为它直接和数据库打交道。这里的数据库可能是本地的,也可能是服务器上的,M会从数据库获取数据,也可能把数据上传给数据库。M也将提供属性或者接口来供C访问其持有的数据。我们就拿一个简单的需求作为例子,假如我想在一个模块中显示一段文字,这段文字是从网上获取下来的。
那么使用MVC的话,在C中肯定需要一个UILabel(V)作为属性来显示这段文字,而这段文字由谁来获取呢,肯定是由M来获取了。
1.2 MVVM(Model View ViewModel):
1.2.1 诞生原因:
由于在MVC模式下,数据解析是放到controller里面进行处理的,而现如今随着产品功能越来越复杂,controller从model中获取到的原始数据需要经过的数据处理也越来越复杂,因此导致了Controller部分越来越臃肿。并且还有相当重要的一点:Controller被设计出来并不是处理数据解析的。因此专门为数据解析创建出了一个新的类:ViewModel。这就是MVVM的诞生。
为什么MVVM这个名字里面,没有Controller的出现(为什么不叫MVCVM,C去哪了)?
你只需要记住两点:
- 1、Controller的存在感被完全的降低了;
- 2、VM的出现就是Controller存在感降低的原因。
MVVM中,Controller不再像MVC那样直接持有Model了。想象Controller是一个Boss,数据是一堆文件(Model),如果现在是MVC,那么数据解析(比如整理文件)需要由Boss亲自完成,然而实际上Boss需要的仅仅是整理好的文件而不是那一堆乱七八糟的整理前的文件。所以Boss招聘了一个秘书,现在Boss就不再需要管理原始数据(整理之前的文件)了,他只需要去找秘书:你帮我把文件整理好后给我。
那么这个秘书就首先去拿到文件(原始数据),然后进行整理(数据解析),接下来把整理的结果给Boss。所以秘书就是VM了,并且Controller(Boss)现在只需要直接持有VM而不需要再持有M了。如果再进一步理解C、VM、M之间的关系:因为Controller只需要数据解析的结果而不关心过程,所以就相当于VM把“如何解析Model”给封装起来了,C甚至根本就不需要知道M的存在就能把工作做好。那么我们MVVM中的持有关系就是:C持有VM,VM持有M。
所以在实现MVVM中一种必要的思想就是:
一旦在实现Controller的过程中遇到任何跟Model(或者数据)相关的问题,就找VM要答案。
2.Qt DEMO的架构和功能设计
2.1 架构设计
采用MVC和MVVM混合架构(一开始不知道需求这么多,因此采用MVC架构,后面根据需求将部分功能模块的MVC架构变成MVVM架构)
2.2 功能设计
整个Qt DEMO分为三大功能部分:倒入导入 播放 转换输出
2.2.1 文件导入
通过饿汉单例模式创建接口的实例话对象
分析导入文件格式和基本信息
3.Qt中用到了哪些设计模式思维
单例模式:
意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
主要解决:一个全局使用的类频繁地创建与销毁。
何时使用:当您想控制实例数目,节省系统资源的时候。
如何解决:判断系统是否已经有这个单例,如果有则返回,如果没有则创建。
关键代码:构造函数是私有的,指向本身实例的类属性为静态,通过一个static静态成员方法返回唯一的对象实例
饿汉模式:
饿汉式单例模式,程序启动时就实例化了该对象,并没有推迟到第一次使用该对象时再进行实例化;如果运行过程中没有使用到,该实例对象就被浪费掉了。
1 | class CSingleton { |
懒汉模式:
懒汉式单例模式,要使用时候在进行对象的实例化。
1 | class CSingleton { |
在多线程情况下的饿汉模式和懒汉模式:
饿汉单例模式的线程安全特性
饿汉单例模式中,单例对象定义成了一个static静态对象,它是在程序启动时,main函数运行之前就初始化好的,因此不存在线程安全问题,可以放心的在多线程环境中使用。
懒汉单例模式的线程安全特性
getInstance是个不可重入函数,也就它在多线程环境中执行,会出现∫问题。因此需要考虑加锁
1 | class CSingleton |
4.怎么封装2Dto3D算法
因为2Dto3D源代码丢失,只有编译后的32位的DLL文件,为了在64位的程序中调用该算法,采用Visual Studio提供的ATL来创建进程外COM组件服务。
ATL创建进程外COM组件服务(C++图解说明)_pathfinder1987的博客-CSDN博客_com服务
5.底层SDK用到了哪些设计模式
主要通过类工厂模式音视频流和每个特效filter链接起来
5.1 简单工厂模式:
结构组成:
工厂类(ShoesFactory):工厂模式的核心类,会定义一个用于创建指定的具体实例对象的接口。
抽象产品类(Shoes):是具体产品类的继承的父类或实现的接口。
具体产品类(NiKeShoes\AdidasShoes\LiNingShoes):工厂类所创建的对象就是此具体产品实例。
优点与不足:
优点: 结构简单,管理方式简单
缺点: 扩展性非常差,新增产品的时候,需要去修改工厂类。
1 | // 音视频流抽象类 |
1 | int main() |
5.2 工厂方法模式
和简单工厂模式中工厂负责生产所有产品相比,工厂方法模式将生成具体产品的任务分发给具体的产品工厂
结构组成:
抽象工厂类厂(ShoesFactory):工厂方法模式的核心类,提供创建具体产品的接口,由具体工厂类实现。
具体工厂类(NiKeProducer\AdidasProducer\LiNingProducer):继承于抽象工厂,实现创建对应具体产品对象的方式。
抽象产品类(Shoes):它是具体产品继承的父类(基类)。
具体产品类(NiKeShoes\AdidasShoes\LiNingShoes):具体工厂所创建的对象,就是此类。
优点与不足:
优点: 工厂方法模式抽象出了工厂类,并把具体产品对象的创建放到具体工厂类实现。实现了一个工厂生产一类产品,不需要修改工厂类,只需要增加新的具体工厂类即可。
缺点: 每新增一个产品,就需要增加一个对应的产品的具体工厂类。相比简单工厂模式而言,工厂方法模式需要更多的类定义。
⚠️:抽象工厂类,提供了创建具体工厂类的纯虚函数,并通过具体工厂类来返回具体产品类
1 | // 总厂 |
1 | int main() |
5.3 抽象工厂模式
上面两种模式不管工厂怎么拆分抽象,都只是针对一类产品,如果需要多种产品,那就需要使用抽象工厂模式。抽象工厂模式通过在AbstarctFactory中增加创建产品的接口,并在具体子工厂中实现新加产品的创建,当然前提是子工厂支持生产该产品。否则继承的这个接口可以什么也不干。
结构组成(和工厂方法模式一样):
抽象工厂类厂(ShoesFactory):工厂方法模式的核心类,提供创建具体产品的接口,由具体工厂类实现。
具体工厂类(NiKeProducer):继承于抽象工厂,实现创建对应具体产品对象的方式。
抽象产品类(Shoes\Clothe):它是具体产品继承的父类(基类)。
具体产品类(NiKeShoes\NiKeClothe):具体工厂所创建的对象,就是此类。
优点与不足:
优点: 提供一个接口,可以创建多个产品族中的产品对象,同一类的多个产品对象不需要创建多个工厂。
缺点: 相比简单工厂模式而言,抽象工厂模式需要更多的类定义。
1 | // 基类 视频流 |
1 | int main() |
5.4 三种工厂模式总结:
特点:
简单工厂模式:一个工厂N个产品
工厂模式:N个工厂N个产品
抽象工厂模式:N个工厂M个产品
缺点(相对):
简单工厂模式:违背了开放封闭原则(改动源码),产品多了会比较杂
工厂模式:产品多了会很杂,代码量稍大,产品多了会比较杂
抽象工厂模式:违背了开放封闭原则(改动源码),代码量大,产品多了会比较非常杂
优点(相对):
简单工厂模式:代码量小,方便添加新的产品
工厂模式:不违背了开放封闭原则(不改动源码),方便添加新的产品
抽象工厂模式:模式灵活,调用方便
6.合并转换功能用到了哪些设计模式,以及如何进行合并转换的
合并转换的功能是:将多个音视频文件合并成一个,并进行编码输出。这里用到了观察者模式
具体思路是:
在视频,音频轨道各设置一个观察者,通过DTS,PTS来检查当前文件的视频,音频幕是否转换完成。当且仅当视频流轨道,音频流轨道均转换完成后,才进行下一个文件的音视频转换工作;若视频流轨道先转换完成的话,那么就对视频流进行插入黑帧,直到音频流轨道转换完成;若是音频流轨道先转换完成的话,那么就对音频流进行插入静音数据处理,直到视频流轨道转换完成。通过这种插帧补数据的方式让每个文件音视频流对齐。
1 | ⚠️:⾳频中DTS和PTS是相同的。 |
观察者模式原理:
观察者模式分为两个角色:观察者和监听者
观察者:
- 通知对于该事件感兴趣的监听者去处理
- 注册
监听者:处理事件
目标 Subject (事件)提供依赖于它的观察者 Observer 的注册(Attach)和注销(Detach)操作,并且提供了使得依赖于它的所有观察者同步的操作(Notify)。观察者 Observer 则提供一个 Update 操作,注意这里的 Observer 的 Update 操作并不在 Observer 改变了 Subject 事件目标状态的时候就对自己进行更新,这个更新操作要延迟到 Subject 对象发出 Notify 通知所有Observer 进行修改(调用 Update)。
观察者模式的使用场景:
1、当一个抽象模型有两个方面,其中一个方面依赖于另一个方面。可将这二者封装在独立的对象中以使它们可以各自独立的改变和复用;
2、当一个对象的改变需要同时改变其它对象,而不知道具体有多少对象有待改变;
3、当一个对象必须通知其他对象,而它又不能假定其它对象是谁,即这些对像都是松耦合的。
1 |
|