随笔编程杂谈录:[-封装-]

作者: e4e52c116681 | 来源:发表于2019-02-16 18:26 被阅读15次

制造轮子和创造轮子两者的区别在于:一者为复用,一者为封装

一、与封装的初遇

现在回到第一次我接触封装的时候:

两年前,class这个词进入了我的世界,但class并不是我封装思想的启蒙师。
在此之前,让我初次领略封装的强大之物是电子元件的引脚和它的真值表。
下面的例子希望你可以好好理解一下:怎么在逻辑上实现一位二进制的加法的逻辑运算单元  
如果你看不下去,就直接return到第6小点

1.与门(AND)和非门(NOT)

你觉得很简单?(少年,你对于力量一无所知)
下面的两个东西的组合是计算机逻辑单元的一切

与门和非门.png
------与门真值表--------------------------非门真值表----------
 输入A  输入B   输出Y                   输入A   输出Y   
 0      0       0                       0       1
 0      1       0                       1       0
 1      0       0                       
 1      1       1     
 -------------------------------------------------------------
 简单解释一下: A和B你可以看成两根导线,只有高电平和低电平两种形式  
 1代表高电平,0代表低电平: 对于A B的每次输入,通过非门都会进行输出,
 真值表就列出了这个元件的所有输入对应输出的情况表

2.一位加法的逻辑设计

首先我们要明确一位加法的逻辑是什么样的

0 + 0 = 0     0 + 1 = 1    0 + 1 = 1     1 + 1 = 0 (超出长度1溢出)
如果将输入A和B看做加数 ,结果看成Y:可以画出下面的真值表:   

--------------------------元件真值表-------------------------
 输入A  输入B   输出Y           
 0      0       0            
 0      1       1            
 1      0       1            
 1      1       0    
 -------------------------------------------------------------
|--而现在需要做的就是如何通过与门和非门的拼接来形成一个元件
|--使得这个真值表成立,你可以验证一下上面的四种情况:
比如 A B 都输入高电压(即1),来校验一下
上面:非A 得 0 ---> 0 与 B 得 1   --->  取非得 0
                                                --->0 与 0 得 0  即输出Y是0
下面:非B 得 0 ---> 0 与 A 得 1   --->  取非得 0

1位加法器.png
这里简单说一下怎么知道要这样画: 
注:这里为了方便书写,用位运算的符号表述,~ 代表非 &代表与 |代表或

--------------------------元件真值表-------------------------
 输入A  输入B   输出Y           
 0      0       0            
 0      1       1            
 1      0       1            
 1      1       0     
-------------------------------------------------------------
[1].找出Y=1的所有行  
[2].写出上步中的逻辑表达式并用或连接 (~A & B) | ( A & ~B)
[3].通过与和非替换掉或: 替换公式 X|Y = ~(~X & ~Y)
~((~(~A & B)) & (~(A & ~B)))  
[4].根据与非关系自内向外画图:
|---上行:~A 即上面的 非门A,然后和 B 一起进入或门 ,结果再取非 即:~(~A & B) 
|---下行:~B 即下面的 非门B,然后和 A 一起进入或门 ,结果再取非 即:~(A & ~B)
|---上下两行的结果进入或门,之后再入非门 ~((上行结果) & (下行结果))

3.加法器封装

说到这里貌似和封装也搭不上啊?但我已经实现了一个逻辑单元
这个单元可以将两个输入按照1位二进制的逻辑运行,于是封装的价值便体现了
现在将输入的线连起来之后,再套上一个外壳,它便是一个有逻辑价值独立元件

1位加法器.png 1位加法器.png
4.进位器逻辑封装

首先我们要明确进位的逻辑是什么样的

逻辑单元:0 + 0 = 0     0 + 1 = 0    1 + 0 = 0     1 + 1 = 1 

--------------------------元件真值表-------------------------         
 输入A  输入B   输出Z           
 0      0       0            
 0      1       0            
 1      0       0            
 1      1       1 
 -------------------------------------------------------------
 
按照上面的步骤来: A & B  发现原来一个与门就能进行进位操作

现在封装的价值就体现了,也就是轮子的价值,可复用,
现在将两个元件进行组装,再加个套子,就能实现更复杂些的逻辑处理单元

加法器.png
5.小结

对使用者而言:哥管你里面什么逻辑,我给输入,你给我我想要的输出就行了
确实一个封装体就做到了,隐藏内部的逻辑实现,将最简洁的使用方式告诉使用者
下面的一幅图和上面的封装体能完成相同的功能,你更用哪个?

加法器.png
--------------元件真值表------------------         
 输入A  输入B    输出Z   输出Y     
 0      0        0       0       
 0      1        0       1       
 1      0        0       1    
 1      1        1       0       
 
这是将Z,Y两个输出存顺序排列: 0+0=00  0+1=01  1+0=01  1+1=10 
而这个进一位加法器的逻辑单元已经完善了,就可以当做一个元件来使用
 
形象而简洁地描述一下:
 在执行  1 + 1 的时候
 高电平经过A,高电平经过B,通过电子元件的内部逻辑单元CRA输出1,通过ADD输出0,
 即 Z输出 1,Y输出 0 ,按Z Y进行输出的到了结果 10  

为了更形象说明,这里拿一个74HC138N看一下,大概三毛钱一个,
传说中的三八译码器,以前玩单片机做电子钟的时候用到过,现在差不多忘完了...

IMG20190215193730.jpg 74HC138.png

在此强调一点:电子元件内部是封装符合真值表的逻辑单元
电子元件都有输入和输出,即输入+ 逻辑单元处理 ----> 希望的输出
至此为止,不再延伸,有兴趣的自己玩...


6. 升华

我们针对输入输出暴露引脚,将逻辑单元封装其中
这样对于指输入就会有期望的输出,在便是逻辑单元的封装
它在软件领域有一个俗称:轮子,这里暂时称为封装体

封装体的优越之处:(只要封装体能实现预期的功能,那么:)
|--无论时间,空间的变化,你的输入都会变成你期望的输出
|--这便具有可复用性,再需要它时便无需再次设计
|--隐藏内部的逻辑实现,以保护封装体的内部封装不被破坏
|--仅暴露接口提供输入和输出,简化使用方式

下面关于封装做一个类比:

-- 电子元件 电脑 开源类库
封装物 硬质外壳 塑料/金属外壳 .jar,.so包等 躯壳
接口 引脚 键盘,USB,电源键等 api方法 口 ,耳,眼,鼻,皮肤
输入 高低电平 键盘输入,U盘头 方法调用 食物,音乐,书籍,气味,触摸
输出 运算结果 屏幕显示,U盘信息 运算结果 能量,思想,劳动力,汗液等
处理核心 逻辑单元 CPU 大脑
使用前提 真值表 说明书 API文档 不可描述(宇宙造物手册?)
核心组成元 与门+非们 各种电子元件 属性+方法 脱氧核糖核酸

7.封装没有缺点吗?

我还没发现世上有什么东西没有缺点

就连我们这么伟大的人类都可能发生基因突变,更何况是人类制造的封装体  

对于电子元件来说,由于环境因素,人为因素可能导致元件内部的损坏,
而无法拆封的你只能选择更换一个封装体,这就造成了浪费,虽然在我们眼里不算什么  

对于一个开源框架来说,一个bug可能导致所有使用者的崩溃,这是很严重的  
也就是使用一个封装体是具有一定的风险性的,当然大厂的框架会相对完善

再者就是接口的复杂,有种必须按照别人意志去做的压迫感  
没有真值表和接口图,使用的人来说是灾难,这种感觉就像...
必须使用的类库没有API文档,并且方法命名为a(),b(),c()一样让人抓狂
可惜对于人类,宇宙并没有留下一份API文档,一切都要靠我们自己来编写...

好了,引入完成,下面进入正文


二、编程中初遇封装

1.与class的初遇

两年前,一开始class 以及它 的 private 是我非常难理解的
对类的认识是在C++里,印象最深的是圆这个类,从获取圆的面积开始

---->[头文件]-------------------
#ifndef BSAE_CIRCLE_H
#define BSAE_CIRCLE_H
class Circle {
    const double PI = 3.141592654;
public:
    double getArea();
    double getRadius() const;
    void setRadius(double radius);
private:
    double mRadius;
};
#endif //BSAE_CIRCLE_H

---->[cpp文件]-------------------
#include "Circle.h"
double Circle::getArea() {
    return mRadius * mRadius * PI;
}

double Circle::getRadius() const {
    return mRadius;
}

void Circle::setRadius(int radius) {
    mRadius = radius;
}

---->使用类----------------
#include <iostream>
#include "circle/Circle.h"

int main() {
    Circle circle;
    circle.setRadius(10);
    std::cout << circle.getArea() << std::endl;
    return 0;
}


2.现在来看

一个类便是类的设计者对于某种概念的封装
我理解类存在的意义确实费了不少时间,当时疑问:
为什么一行代码解决的事要拆成一个类?而且又是头又是cpp的

现在发现有这种疑问的根源在于当时没有认清自己的角色  
认清自己的角色,这对入门的人来说是非常困难的,类的本身就是一个逻辑处理单元
而程序员的角色是设计类的人,就像电子元件的设计者在设计逻辑单元一样  

但任何一个程序员都必定是第一个使用者,所以两个角色在同一个人身上 
对于入门的来说,只能是一个使用者,因为你只是在意获取结果,而没有程序员的设计之魂
就会感觉很混乱,站在一个使用者的角度,类确实将半径为10的圆面积这个问题变得复杂了  
关系.png

但如果封装的思想到位,就可以明确这个类的价值
setRadius进行输入,getRadius,getArea进行输出,其中的一切都是逻辑单元

内部分析.png

如果你还不清楚,看下图:这就是封装
看不见内部了,该怎么用? 电子元件有真值表,类有API文档
至此我想对于类和封装的关系应该讲的淋漓尽致了

封装.png
----------Circle API--------------------------
double getArea(); 获取圆的面积
double getRadius(); 获取圆的半径
void setRadius(double radius); 设置圆的半径
-----------------------------------------------

当你在非Circle中使用的时候,你的角色就变成了Circle元件的用户
你需要关注的就只用它的输入和输出,内部逻辑实现已经不需要你考虑了
不过一旦你进入了Circle中,你的角色就是Creator,你可以把自己当成造物主来实现逻辑单元

Circle circle;
circle.setRadius(10);
circle.getArea()//314.159

相关文章

  • 随笔编程杂谈录:[-封装-]

    制造轮子和创造轮子两者的区别在于:一者为复用,一者为封装 一、与封装的初遇 现在回到第一次我接触封装的时候: 1....

  • 随笔编程杂谈录--《隆中对》

    注:本篇非技术文,只是一些个人总结感触,不喜欢的出门左走 《隆中对》----张风捷特烈 是混乱还是进化 哪种语言好...

  • 杂谈与随笔之别

    杂谈栏目已许久没有更新了,在我看来,相比于随笔集,杂谈更多的是聚焦我个人的当日心得与生活。如此一来,杂谈与随笔...

  • 2018-04-13

    随笔杂谈 本就不是文人骚客,奈何上了...

  • b etter

    不会封装,如何编程; 不会封装,如何精通。

  • python 面向对象封装案例

    面向对象封装案例 目标 封装 小明爱跑步 存放家具 01. 封装 封装 是面向对象编程的一大特点 面向对象编程的 ...

  • 14.Python对象封装

    面向对象封装案例 目标 封装 小明爱跑步 存放家具 01. 封装 封装 是面向对象编程的一大特点 面向对象编程的 ...

  • 面向对象封装案例

    目标 封装 小明爱跑步 存放家具 01. 封装 封装 是面向对象编程的一大特点 面向对象编程的 第一步 —— 将 ...

  • python 面向对象封装案例 II

    面向对象封装案例 II 目标 士兵突击案例 身份运算符 封装 封装 是面向对象编程的一大特点 面向对象编程的 第一...

  • Javascript基础进阶(十六)JS中面向对象的理解、继承、

    面向对象编程OOP 它是一种编程思想,我们的编程或者学习其实是按照 类、实例来完成的类: 继承、封装、多态 封装...

网友评论

    本文标题:随笔编程杂谈录:[-封装-]

    本文链接:https://www.haomeiwen.com/subject/xysieqtx.html