Skip to content
Published at:

LVGL中的一些设计原则

上上周在改一个框架,当然,是基于别人的框架来改,改了两天之后发现有点不太对劲,把原有框架的拓展性改没了。然后就去重新刷了下设计原则。当然,我们的框架不需要太多的拓展性,因为太多的拓展性意会让使用的难度变大,这些就是满大街的大而全的通用框架,面向的是能用的场景;我们框架的目标可能就是对特殊场景的优化,然后让人简单的设置就能用起来。

软件设计七大原则

设计原则定义目的
开闭原则对扩展开放,对修改关闭降低维护带来的新风险
依赖倒置原则高层不应该依赖低层,要依赖于抽象,不要依赖于具体实现(面向接口编程)更利于代码结构的升级扩展
单一职责原则一个类只干一件事,实现类要单一便于理解,提高代码的可读性
接口隔离原则一个接口只干一件事,接口要精简单一功能解耦,高聚合、低耦合
迪米特法则最少知识原则,不该知道的不要知道,一个类应该保持对其它对象最少的了解,降低耦合度只和朋友交流,不和陌生人说话,减少代码臃肿
里氏替换原则不要破坏继承体系,子类重写方法功能发生改变,不应该影响父类方法的含义防止继承泛滥
合成复用原则尽量使用组合或者聚合关系实现代码复用,少使用继承降低代码耦合

设计原则和设计模式的关系

设计模式分类:

  • 创建型模式:工厂模式、抽象工厂模式、单例模式、建造者模式、原型模式
  • 结构型模式:适配器模式、桥接模式、过滤器模式、组合模式、装饰器模式、外观模式、享元模式、代理模式
  • 行为型模式:责任链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、空对象模式、策略模式、模板模式、访问者模式

关系:

设计模式是设计原则的应用、实现。设计原则是底层原则、是根本;设计模式里面的套路用了设计原则。简单的讲,你写的代码可以没有使用设计模式,但一定不能没有设计原则

C语言和面向对象

先讨论下C++

C++作者:Bjarne Stroustrup

C++是一个多范式的语言;包括支持面向对象,也被有人称为“C with Classes”;

CFront:C++原始的编译器,作用把C++代码转成C代码;为啥叫CFront?在C的编译器前面加了一个编译器,把C++代码通过CFront转成C代码,然后用C编译器去编译生成程序

面向对象:

问题:C++中的高级特性如何在C中表示?

  • 类里面的函数真的属于这个Class吗?sizeof()
  • 类中的this怎么来的?语法糖而已;有些语言会显示写self(Python、Rust)
  • 类调用成员函数是怎么回事?语法糖,和调用普通全局函数并没有什么区别

C++的虚函数、Java的Interface,Rust的Trait

父类定义接口,然后子类有不同的实现,在实际运行的时候会调用不同的子类实现, 下图中的接口函数本质上是一个函数指针变量,在使用时指定了不同的子类的实现的函数

设计原则和LVGL

S单一职责:

一个类只负责完成一个职责或者功能

  • 目录的命名
  • 源代码文件的命名

依赖倒置原则

定义:高层不应该依赖低层,要依赖于抽象,不要依赖于具体实现(面向接口编程)

目的:更利于代码结构的升级扩展

问题:依赖于抽象?这里的抽象指的是什么?

LVGL中扩展使用:

  • lvgl如何显示到不同的屏幕?
  • lvgl如何获取不同屏幕的点击坐标?
  • lvgl如何显示不同格式的图片?

lvgl如何显示到不同的屏幕?

框架怎么写?
  1. xxx
  2. xxx
  3. 显示到屏幕(估计就会写死)
  4. xxx
改完后?
  1. LVGL框架定义接口:void (*flush_cb)(struct _disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);
    • 我框架内部会在需要的时候去调这个函数
    • 把对应的数据给你:哪块区域的屏幕要刷新area,以及这块区域对应的数据值color_p
  2. 对应的拓展自己去处理数据:通过SDL刷到屏幕;通过Framebuffer刷到屏幕:和不同平台,实现相关

lvgl如何获取不同屏幕的点击坐标?

框架怎么写?
  1. xxx
  2. xxx
  3. 获取屏幕点击的坐标(估计就又会写死)
  4. xxx
改完后?
  1. LVGL框架定义接口:bool (*read_cb)(struct _lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
    • 我框架内部会在需要的时候去调这个函数
    • 我框架把这个结构体指针data给你:你负责把对应点击的坐标填进去,然后我框架内部要用(传递到对应控件的点击回调函数)
  2. 具体的实现如何去填充数据

上面两者的区别:

  • 显示:一个是把数据给你,实现负责去使用这些数据
  • 点击:我把结构休指针给你,实现负责把数据填充进去

lvgl如何显示不同格式的图片?

通过实现图片解码器,实现对应函数回调。步骤同上......

现实生活:公司做项目的例子

  • 依赖反转前:我领导依赖于我,我的任务完成了,他的项目才能算完成
  • 依赖反转后:我领导提出标准,提供对应的资源;我拿到标准和资源,然后去实现

一开始领导依赖于我的工作,他的任务就算完成;我依赖于我领导给的标准和资源去完成这个任务;另外的一个变化是:对于前者,你的领导可能会控制你的细节(不能用这个,得用那个;不能这样搞,要那样搞);对于后者,我领导就成了标准的制定者

抽象的定义:

  • 需要对业务有足够的了解,对问题抽象
    • 回调中的参数:能够实现拓展;不要出现冗余的参数
  • 抽象标准的要求
    • Android的UI线程:死循环不停的去调回调,用户写的ui代码,用户写的事件代码;这些代码得满足一定的要求,比如说:不能卡太久;你卡住了,我内部的死循环就被这个卡死

References:

Updated at: