面向对象编程与面向过程编程和函数式编程之间的区别

目录

1.引言

2.面向过程编程

3.面向对象编程和面向过程编程的对比

4.函数式编程

5.面向对象编程和函数式编程的对比


1.引言

        面向对象编程是现在流行的编程范式(编程风格)。实际上,除面向对象编程以外,大家熟悉的编程范式还有另外两种:面向过程编程和函数式编程。随着面向对象编程的出现,面向过程编程已经逐渐退出了历史舞台,函数式编程目前还没有被程序员广泛接受,只能作为面向对象编程的补充。为了更好地理解面向对象编程,我们在本节中补充讲解面向过程编程和函数式编程,并且将面向对象编程与面向过程编程和函数式编程进行对比。

2.面向过程编程

        什么是面向过程编程语言?实际上,我们可以通过对比面向对程和面向对象编程语言这两个概念来理解它们。类比面向对象编程与面向对象编程的定义,面向过程编程和面向过程编程语言的定义如下。

        1)面向过程编程也是一种编程范式或编程风格。它以过程(可以理解为方法、函数和操作)作为组织代码的基本单元,以数据(可以理解为成员变量、属性)与方法相分离为主点。面向过程编程风格是一种流程化的编程风格,通过拼接一组顺序执行的方法来操作数据实现一项功能。

        2)面向过程编程语言的主要特点是不支持类和对象这两个语法概念,不支持丰富的面对象编程特性(如继承、多态和封装),仅支持面向过程编程。

        不过,这里必须声明一点,就像之前提到的面向对象编程和面向对象编程语言没有官方义一样,这里给出的面向过程编程和面向过程编程语言的定义也并不是严格的官方定义。之以给出这样的定义,只是为了与面向对象编程和面向对象编程语言进行对比,方便读者理解们之间的区别。

        因为定义不是很严格,也比较抽象,所以我们再用一个例子进一步解释。假设有一个记录了用户信息的文本文件users.txt,每行文本的格式为name&age&gender(如小王&28&男)我们希望编写一个程序,从uers.txt文件中逐行读取用户信息,然后将其格式化为name\tag\tgender(其中,\t是分隔符)这种文本格式,并且按照 age对用户信息进行从小到大排序之后重新将其写入另一个文本文件fommatted_users.txt中。针对这样一个功能需求,我们分析以下利用面向过程编程和面向对象编程这两种编程风格编写的代码有什么不同。

        我们先看一下利用面向过程编程这种编程风格编写的代码是什么样子的。注意,下面这代码是利用C语言这种面向过程编程语言编写的。

struct User{char name[64];int age;char gender[16];
};struct User parse_to_user(char* text){//将文本("小王&28&男”)解析成结构体User
}char* format_to_text(struct User user) {//将结构体user格式化为文本(小王\t28\t男)
}void sort_users_by_age(struct User user[]){//按照年龄大小排序
}void format_user_file(char* origin_file_path, char* new_file_path){//省略打开文件的代码struct User user[1024];int count = 0;while (true){struct User user = parse_to_user(line);users[count++] = user;}sort_users_by_age(users);for (int i = 0; i < count; i++){char* formatted_user_text = format_to_text(users[i]);//此处省略写入新文件的代码}//省略关闭文件的代码
}int main(char** args, int argv){    format_user_fle("/home/zheng/users.txt","/home/zheng/formatted users.txt");return 0;
}

        我们再看一下利用面向对象编程这种编程风格编写的代码是什么样子的。注意,下面这段代码是利用Java这种面向对象编程语言编写的。

public class User {private String name;private int age;private String gender;public User(String name,int age,String gender){this.name = name;    this.age = age;this.gender = gender;}public static User praseFrom(String userInfoText){//将文本("小王&286男")解析成类User}public String formatToText(){//将类User格式化为文本("小王\t28\t男”)}
}public class UserFileFormatter{public void format(String userFile,String formatteduserFile){//此处省略打开文件的代码List users =new Arraylist<>();while(1){//将文件中的数据读取到userTextUser user =User.parseFrom(userText);users.add(user);}/此处省略按照年龄从小到大排序users的代码for(int i= 0:i <users.size(); ++i){String formattedUserText = user.formatToText();//此处省略写入新文件的代码}//此处省略关闭文件的代码}
}public class MainApplication{public static void main(sring[] args){UserFileformatter userFileFormatter =  new UserFileFormatter();userFileFormatter.fomnat("/home/zheng/users.txt", " /home/zheng/formatted_users.txt");}
}

        从上述两段代码中,我们可以看出,面向过程编程和面向对象编程的基本区别就是的组织方式不同。面向过程编程风格的代码被组织成一组方法的集合及其数据结构(如User),并且方法和数据结构的定义是分开的。面向对象编程风格的代码被组织成一组类。方法和数据结构被绑定在一起,定义在类中。

        分析完上面两段代码,一些读者可能会问,面向对象编程和面向过程编程的区别就这吗?当然不是,关于这两种编程风格的更多区别,请读者继续往下看。

3.面向对象编程和面向过程编程的对比

        在上面章节中,我们介绍了面向过程编程和面向过程编程语言的定义,并将它们与面向对象编程和面向对象编程语言进行了对比。接下来,我们介绍一下面向对象编程为什么能够取代面向过程编程,并成为目前主流的编程范式。相比面向过程编程,面向对象编程有哪些优势?

        (1)面向对象编程更加适合应对大规模复杂程序的开发

        通过上面章节中格式化文本文件的例子,读者可能感觉两种编程范式实现的代码相差不多无非就是代码的组织方式有区别,没有感受到面向对象编程的明显优势。之所以一些读者有这种感受,主要是因为这个例子的程序比较简单,不够复杂。

        对于简单程序的开发,无论是使用面向过程编程风格,还是使用面向对象编程风格,二者实现的代码的差别确实不会很大,有时,甚至面向过程编程风格更有优势,因为需求相当简单,整个程序的处理流程只有一条主线,很容易被划分成顺序执行的几个步骤,然后逐个步骤翻译成代码,这就非常适合采用面向过程这种“面条”式的编程风格。

        但对于复杂的大规模程序的开发,整个程序的处理流程错综复杂,并非只有一条主线。如果我们把整个程序的处理流程画出来,那么它会是一个网状结构。此时,如果我们再用面向过程编程这种流程化、线性的思维方式“翻译”这个网状结构,以及思考如何把程序拆解成一组顺序执行的方法,就会比较吃力。这个时候,面向对象编程风格的优势就体现出来了。

        在面向对象编程中,我们以类为思考对象。在进行面向对象编程时,我们并不是一开始思考如何将复杂的流程拆解为一个个方法,而是采用“曲线救国”的策略,先思考如何给业务建模、如何将需求翻译为类和如何在类之间建立交互关系,而完成这些工作完全不需要考虑错综复杂的处理流程。当我们有了类的设计之后,再像搭积木一样,按照处理流程,将类进行组装,形成整个程序。这种开发模式和思考问题的方式能够让我们在应对复杂程序开发时的思路更加清晰。

        除此之外,面向对象编程还提供了一种模块化的代码组织方式。例如,一个电商交易系统的业务逻辆复杂,代码量很大,我们可能要定义数百个函数、数百个数据结构,如何分门别类地组织这些函数和数据结构,才能让它们不会看起来凌乱呢?类是一种非常好的组织这些函数和数据结构的方式,也是一种将代码模块化的有效手段。

        读者可能会说,对于C语言这种面向过程编程语言,我们可以按照功能的不同,把函数和数据结构放到不同的文件里,以达到给函数和数据结构分类的目的,也可以实现代码的模块化。这样说是没错的,只不过面向对象编程本身提供了类的概念,按照类模块化代码是强制进行的,而面向过程编程语言并不强求以何种方式组织代码。

        实际上,利用面向过程编程语言,我们照样可以写出面向对象编程风格的代码,只不过可能比用面向对象编程语言来写面向对象编程风格的代码付出的代价要高一些。而且,面向过程编程和面向对象编程并非完全对立。在很多软件开发中,尽管我们利用的是面向过程编程语言,但也借鉴了面向对象编程的一些优点。

        (2)面向对象编程风格的代码易复用、易扩展和易维护

        在上述文本文件处理的例子中,因为其代码比较简单,所以我们只用到了类、对象这两个基本的面向对象概念,并没有用到高级的四大特性:封装、抽象、继承和多态。面向对象编程的优势其实并没有发挥出来。

        面向过程编程是一种非常简单的编程风格,并没有像面向对象编程那样提供丰富的特性。而面向对象编程提供的封装、抽象、继承和多态特性,能够极大地满足复杂的编程需求,能够方便我们写出易复用、易扩展和易维护的代码,理由有如下4点。

        1)首先,我们来看封装特性。封装特性是面向对象编程与面向过程编程的基本区别,因为封装基于面向对象编程中的基本概念:类。面向对象编程通过类这种组织代码的方式,将数据和方法绑定在一起,通过访问权限控制,只允许外部调用者通过类暴露的有限方法访问数据,而不会像面向过程编程那样,数据可以被任意方法随意修改。因此,面向对象编程提供的封装特性更有利于提高代码的易维护性。

        2)其次,我们来看抽象特性。我们知道,函数本身就是一种抽象,它隐藏了具体的实现。

        在使用函数时,我们只需要了解函数具有什么功能,不需要了解它是怎么实现的。在这一点上,无论是面向过程编程还是面向对象编程,都支持抽象特性。不过,面向对象编程还提供了其他抽象特性的实现方式。这些实现方式是面向过程编程不具备的,如基于接口实现抽象特性。基于接口的抽象,可以在不改变原有实现的情况下,轻松替换新的实现逻辑,提高了代码的可扩展性。

        3)再次,我们来看继承特性。继承特性是面向对象编程相比面向过程编程所特有的两个特性之一(另外一个是多态)。如果两个类有一些相同的属性和方法,我们就可以将这些相同的代码抽取到父类中,让两个子类继承父类。这样,两个子类就可以重用父类中的代码,避免了代码重复编写,提高了代码的复用性。

        4)最后,我们来看多态特性。基于这个特性,在需要修改一个功能实现时,可以通过实现一个新的子类的方式,在子类中重写原来的功能逻辑,用子类替换父类。在实际的代码运行过程中,调用子类新的功能逻辑,而不是在原有代码上做修改。这样,我们就遵守了“对修改关闭、对扩展开放”的设计原则,提高了代码的扩展性。除此之外,利用多态特性,不同类的对象可以传递给相同的方法,复用同样的逻辑,提高了代码的复用性。

        所以说,基于这四大特性,利用面向对象编程,我们可以轻松地写出易复用、易扩展和易维护的代码。当然,我们不能认为利用面向过程编程方式就不可以写出易复用、易扩展和易维护的代码,但没有四大特性的帮助,付出的代价可能要高一些。

        (3)面向对象编程语言更加人性化、高级和智能

        人最初与机器“打交道”是通过0、1这样的二进制指令,后来,使用的是汇编语言,再后来,使用的是高级编程语言。在高级编程语言中,面向过程编程语言又早于面向对象编程语言出现。之所以先出现面向过程编程语言,是因为与机器交互的方式从二进制指令、汇编语言,逐步发展到面向过程编程语言,这是一种自然的过波,而且它们都属于流程化、“面条”式的编程风格,即用一组指令顺序操作数据来完成一项任务。

        从二进制指令到汇编语言,再到面向过程编程语言,与机器交互的方式在不停演进,从我们可以容易地发现一条规律,那就是编程语言越来越人性化,使得人与机器的交互变得趋越容易。笼统来说,编程语言越来越高级。实际上,在面向过程编程语言之后,面向对象语言的出现也顺应了这样的发展规律,也就是说,面向对象编程语言比面向过程编程语言更高级!

        与二进制指令、汇编语言和面向过程编程语言相比,面向对象编程语言的编程套路、处理问题的方式是完全不一样的。前三者使用的是计算机思维方式,而面向对象编程语言使用的人类思维方式。在使用前3种语言编程时,我们是在思考如何设计一组指令,并“告诉”机器去执行这组指令,操作某些数据,完成某个任务。而在进行面向对象编程时,我们是在思考何给业务建模,以及如何将真实世界映射为类,这让我们能够聚焦于业务本身,而不是思考何与机器打交道。可以这么说,编程语言越高级,离机器越“远”,离我们人类越“近”,也就越“智能”。

        接着上述编程语言的发展规律,如果一种具有突破性的新的编程语言出现,那么它肯定更加“智能”。我们大胆想象一下,如果使用这种编程语言,那么我们可以对计算机知识没有任何了解,无须像现在这样一行行地编写代码,只需要写清楚需求文档,编程语言就能自动生成我们想要的软件。

4.函数式编程

        函数式编程并非新事物,它于50多年前就已经出现了。近几年,函数式编程开始重新被人关注,一些非函数式编程语言加入了很多特性、语法和类库来支持函数式编程,如JavaPython、Ruby和JavaScript等。

        什么是函数式编程(Functional Programming)?

        前面讲到,面向过程编程、面向对象编程并没有严格的官方定义。在当时的讲解中,作着只是给出了自己总结的定义。而且,当时给出的定义也只是对两种编程范式主要特性的总结并不是很严格。实际上,函数式编程也是如此,它也没有一个严格的官方定义。因此,作者就从特性方面定义函数式编程。

        严格来讲,函数式编程中的“函数”并不是指编程语言中的“函数”,而是指数学中的“函数”或“表达式”(如y=f(x))。不过,在编程实现时,对于数学中的“函数”或“表达式”我们习惯地将它们设计成函数。因此,如果不深究的话,那么的函数式编程中的函数也可以理解为编程语言中的“函数”。

        每种编程范式都有其独特的地方,这就是它们会被抽象出来并作为一种范式的原因。面向对象编程最大的特点是以类、对象作为组织代码的单元以及它的四大特性。面向过程编程最大的特点是以函数作为组织代码的单元,数据与方法分离。函数式编程独特的地方是他的编程思想。函数式编程”认为”,程序可以用一系列数学函数或表达式的组合来表示。不过,真的可以把任何程序都可以表示成一组数学表达式吗?

        从理论上来讲,这是可以的。但是,并不是所有的程序都适合这样做。函数式编程有它适合的应用场景,如科学计算、数据处理和统计分析等。在这些应用场景中,程序往往容易用数据表达式来表示。在实现同样的功能时,相比非函数式编程,函数式编程需要的代码更少。但是,对于强业务相关的大型业务系统开发,如果我们费力地将它抽象成数学表达式,非要用函数式编程来实现,那么显然是自讨苦吃。在强业务相关的大型业务系统开发场景下,使用面向对象编程更为合适,因为写出来的代码更具可读性和可维护性。

        上面介绍的是函数式编程的编程思想,具体到编程实现,函数式编程与面向过程编程一样,也是以函数作为组织代码的单元。不过,它与面向过程编程的区别在于,它的函数是无状态的。何为无状态?简单来说,函数内部涉及的变量都是局部变量,不像面向对象编程,共享类成员变量,也不像面向过程编程,共享全局变量。函数的执行结果只与入参有关,与其他任何外部变量无关。同样的入参,无论怎么执行,得到的结果都是一样的。我们举个例子来解释

        下面的 imcrease()函数是有状态函数,执行结果依赖b的值,即便入参相同,多次执行函数,函数的返回值有可能不同,因为b的值有可能不同。

int b;
int increase(int a){return a+b;
}

        下面的imcrease()函数是无状态函数,执行结果不依赖任何外部变量值,只要入参相同,无论执行多少次,函数的返回值都相同。

int increase(int a,int b) {return a+b;
}

        前面讲到,实现面向对象编程不一定非得使用面向对象编程语言,同理,实现函数式编程也不一定非得使用函数式编程语言。现在,很多面向对象编程语言提供了相应的语法、类库来支持函数式编程。接下来,我们介绍一下Java这种面向对象编程语言对函数式编程的支持,借此加深读者对函数式编程的理解。我们先看下面这段典型的Java函数式编程的代码。

public class FPDemo{public static void main(stringl] args){Optional<Integer> result = Stream.of("foo", "bar", "hello").map(s-> s.length()).filter(l ->l <=3).max((o1, o2) -> o1 - o2);System.out.printIn(result.get());//输出2}
}

        这段代码的作用是从一个字符串数组中过滤出字符长度小于或等于3的字符串,并且求其中最长字符串的长度。如果读者不了解Java函数式编程的语法,那么可能对上面这段代码感觉有些懵,因为Java为函数式编程引入了3个新的语法概念:Stream 类、Lambd表达式和函数接口(functional interface)。其中,Steam 类的作用是通过它支持用“.”级联多个函数操作的代码编写方式;Lambda表达式的作用是简化代码的编写;函数接口的作用是让我们可以把函数包裹成函数接口,把函数当做参数一样使用(Java不像C支持函数指针那样可以把函数直接当参数来使用)。接下来,我们详细讲解这3个概念。

        (1)Stream类

        假设我们要计算表达式:(3-1)x2+5。如果按照普通的函数调用的方式来编写代码,那么

代码如下。

    add (multiply(subtract (3,1),2), 5)

        这样编写的代码的可读性不好,我们换个可读性更好的写法,如下所示。

    subtract(3,1).multiply(2).add(5);

        我们知道,在Java 中,“.”表示调用关系,即某个对象调用了某个方法。为了支持上的种级联调用方式,我们让每个函数都返回一个通用类型:Stream类对象。在Stream 类上的操作有两种:中间操作和终止操作。中间操作返回的仍然是Stream类对象,而终止操作返园是确定的结果值。

        我们再来看之前的FPDemo类。我们为FPDemo类这段代码添加了注释,如下所示,中,map、filter是中间操作,返回Stream类对象,可以继续级联其他操作;max是终止操作,返回的不是 Stream 类对象,无法继续往下进行级联处理了。具体返回什么类型的数据是由数本身定义的。

public class FPDemo{public static void main(stringl] args){Optional<Integer> result = Stream.of("foo", "bar", "hello").map(s-> s.length())//map返回 Stream<Integer>对象.filter(l ->l <=3)  //filter返回 Stream<Integer>对象.max((o1, o2) -> o1 - o2); //max终止操作,返回Optional<Integer>System.out.printIn(result.get());//输出2}
}

        (2)Lambda 表达式

        前面讲到,引入Lambda表达式的主要作用是简化代码的编写。我们用map函数举例说明。下面列出3段代码,第一段代码展示了map函数的定义,map函数接收的参数是一个Function接口,也就是后续要讲到的函数接口:第二段代码展示了map函数的使用方式;第三段代是使用Lambda表达式对第二段代码简化之后的写法。实际上,Lambda表达式在Java 中只是一个语法糖,底层是基于函数接口实现的,也就是第二段代码展示的写法。

//第一段代码:stream类中map函数的定义
public interface Stream<T> extends BaseStream<T, Stream<T>> {<R> Stream<R> map(Function<? super T, ? extends R> mapper);   //...省略其他函数.
}//第二段代码:Stream类中map的数的使用方式
Stream.of("foo", "bar", "hello").map(new function<String, Integer>(){@Overridepublic Integer apply(String s){return s.length ();}
});//第三段代码: 用lambda表达式简化后的写法
Stream.of("foo", "bar", "hello").map(s -> s.length());Lambda表达式包括3部分:输入、函数体和输出,标准写法如下所示:
(a, b)->{ 语句1; 语句2; ...; return 输出; } //a,b都是输入参数

        实际上,Lambda表达式的写法非常灵活,除上述标准写法以外,还有很多简化写法。例如,如果入参只有一个,那么可以省略“0”,直接写成“a->{….)”;如果没有入参,那么可以直接将输入和箭头都省略,只保留函数体;如果函数体只有一个语句,那么可以将“()”省略:如果函数没有返回值,那么return 语句可以省略。

        如果我们把之前 FPDemo 类示例中的 Lambda 表达式全部替换为函数接口的实现方式,那么如下所示。代码是不是变多了?

0ptional<Integer> result = Stream.of("foo", "bar", "hello").map(s ->s.length()).flter(l -> l <= 3).max((o1,o2)->o1-o2);
//将上述Lambda表达式替换为函数接口的实现方式
0ptional<Integer>result2 = Stream.of("foo", "bar", "hello").map(new Function<String,Integer>(){@Overridepublic Integer apply(String s){return s.length();}}).flter(new Predicate<Integer>(){@Overridepublic boolean test(Integer l){return l<=3;}}).max(new Comparator<Integer>(){@Overridepublic int compare(Integer ol, Integer o2){return ol-o2;}});

        (3)函数接口

        实际上,上面那段代码中的 Function、Predicate和 Comparator 都是函数接口。我们知道,C语言支持函数指针,它可以把函数直接当变量来使用。但是,Java没有函数指针这样的语法,因此,它通过函数接口,将函数包裹在接口中,当做变量来使用。实际上,函数接口就是接口。不过,它有自己特别的地方,那就是要求只包含一个未实现的方法。只有这样,Lambda 表达式才能明确知道匹配的是哪个接口。如果有两个未实现的方法,并且接口入参、返回值都一样,那么Java在翻译Lambda 表达式时,就不知道表达式对应哪个方法。

        为了让读者对函数接口有一个直观的理解,我们把Java提供的Function、Predicate 这两个函数接口的源码列在下面。

@FunctionalInterface
public interface function<T,R>{//只有这一个未实现的方法R apply(T t);default<V> Function<V, R> compose (Function<? super V, ? extends T> before) {            Object.requireNonNull(before);return (V v)->apply(before.apply(v));}default<V> Function<T, V> andThen(Function<? super R, ? extends v> after) {Objects.requireNonNull(after);return (T t)-> after.apply(apply(t));}static <T> Function<T,T> identity(){ return t -> t;}
}@FunctionalInterface
public interface Predicate<T>{boolean test(T  t);//只有这一个未实现的方法default Predicate<T> and(Predicate<? super T> other){Objects.requireNonNull(other);return (t)->test(t) && other.test(t);}default Predicate<T> negate(){return (t)-> !test(t);}default Predicate<T> or(Predicate<? super T> other){Objects.requireNonNull(other);return (t)->test(t)|| other.test(t);}static <T> Predicate<T>  isEqual(Object targetRef){return (null == targetRef)? objects::isNull:object -> targetRef.equals(object);}
}

5.面向对象编程和函数式编程的对比

        不同的编程范式并不是截然不同的,总有一些相同的编程规则。例如,无论是面向过程编程、面向对象编程,还是函数式编程,它们都有变量、函数的概念,顶层都要有main 函数执行入口,以组装编程单元(类、函数等)。只不过,面向对象编程的编程单元是类或对象,面向过程编程的编程单元是函数,函数式编程的编程单元是无状态函数。

        函数式编程因其编程的特殊性,仅在科学计算、数据处理和统计分析等领域才能更好地发挥它的优势。因此,它并不能完全替代更加通用的面向对象编程范式。但是,作为一种补充它有很大的存在、发展和学习意义。

        面向对象编程侧重代码模块的设计,如类的设计。而面向过程编程和函数式编程侧重具的实现细节,如函数的编写、这也是大部分讲解设计模式的图书喜欢使用面向对象编程语言举例的原因。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/7888.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java—异常

异常 什么是异常 异常的体系 编译时异常处理方式 1、选择报错的整个代码块&#xff0c;快捷键crtlaltt键&#xff0c;选择try/catch将代码围起来。 2、编译异常处理方式2 在main方法上抛出异常 自定义异常 例子&#xff1a; 自定义运行时异常 自定义编译时异常 异常…

SpringBoot优雅地定制JSON响应数据

提示&#xff1a;文章若有错误&#xff0c;欢迎评论区指正&#x1f36d; 文章目录 前言 一、如何使用JsonView这个注解&#xff1f; 二、应用场景 三、实战案例 注解方式 编程方式 总结 前言 最近在学习过程中发现了Jackson库的JsonView也可以改变JSON的输出结构&#xff0c;…

QT截图程序,可多屏幕截图

截图程序&#xff0c;支持多屏幕时跨屏幕截图。截图使用setMask达到镂空效果&#xff0c;截图后会有预览和保存功能。截图时按下Esc可退出。 mainwindow.ui mainwindow.cpp #include "mainwindow.h" #include "ui_mainwindow.h" #include <QDebug> …

Ansible自动化运维工具 - playbook 剧本编写

一. inventory 主机清单 Inventory 支持对主机进行分组&#xff0c;每个组内可以定义多个主机&#xff0c;每个主机都可以定义在任何一个或多个主机组内。 1.1 inventory 中的变量含义 Inventory 变量名 含义ansible_hostansible连接节点时的IP地址ansible_port连接对方…

2024-05-07 商业分析-如何在社会层面做一个更好的工具人-记录

摘要: 2024-05-07 商业分析-如何成为一个靠谱的工具人 如何在社会层面做一个更好的工具人 那么今天讲的这个主题呢&#xff0c;对吧&#xff1f;你们一看啊&#xff0c;就觉得这个就不应该我讲是吧啊&#xff0c;但是呢这个逻辑呢我还得跟你们讲一下啊&#xff0c;就是如何成为…

虚幻引擎笔记

虚幻引擎笔记 一、蓝图类二、创建自定义Character蓝图三、操作映射和轴映射 一、蓝图类 Actor&#xff1a;可以放置在关卡中的物体Pawn&#xff1a;相当于游戏角色&#xff0c;可以通过玩家控制器来控制角色&#xff1a;在Pawn的基础上增加了四处走动的功能。创建游戏角色时使用…

Freeswitch-mod开发

文章目录 一、Freeswitch-mod开发1.1 介绍1.2 实战1.2.1 新建一个mymod.c或者mymod.cpp1.2.2 新建一个Makefile1.2.3 编译 二、Freeswitch-mod-自定义Dialplan模块2.1 介绍2.2 实战2.2.1 改造mymod.c&#xff08;代码是完整的&#xff0c;自己做区别看一下&#xff09;2.2.2 编…

python实验三 实现UDP协议、TCP协议进行服务器端与客户端的交互

实验三 实验题目 1、请利用生成器构造一下求阶乘的函数Factorial()&#xff0c;定义一个函数m()&#xff0c;在m()中调用生成器Factorial()生成小于100的阶乘序列存入集合s中&#xff0c;输出s。 【代码】 def factorial():n1f1while 1:​ f * n​ yield (f)​ n1…

XORM 框架的使用

1、xorm 1.1、xorm 简介 xorm 是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作非常简便。 特性 支持 struct 和数据库表之间的灵活映射&#xff0c;并支持自动同步事务支持同时支持原始SQL语句和ORM操作的混合执行使用连写来简化调用支持使用ID, In, Where, Limit,…

Java jar程序CPU异常高问题排查

文章目录 一、命令排查二、脚本排查方法一 curl脚本文件直接用bash运行方法二 下载脚本文件并运行一、命令排查 1.使用 top 定位到占用CPU高的进程PID top2.获取进程PID信息 ps aux | grep [PID]3.找到占用CPU高的线程 ps -mp [PID

Python批量计算多张遥感影像的NDVI

本文介绍基于Python中的gdal模块&#xff0c;批量基于大量多波段遥感影像文件&#xff0c;计算其每1景图像各自的NDVI数值&#xff0c;并将多景结果依次保存为栅格文件的方法。 如下图所示&#xff0c;现在有大量.tif格式的遥感影像文件&#xff0c;其中均含有红光波段与近红外…

JAVA基础jsp之富文本编辑器文件上传与下载

目录 一、富文本编辑器 二、SmartUpload插件 一、富文本编辑器 1.概述 富文本编辑器&#xff0c;Rich Text Editor, 简称 RTE, 是一种可内嵌于浏览器&#xff0c;所见即所得的文本编辑器&#xff0c;类似于 Microsoft Word 的编辑功能。 2.常用富文本编辑器 ①ckedi…

通过氧气退火增强β-Ga₂O₃二极管.中国科技大学和河北半导体研究所的研究人员在这一特定领域取得了最新重大进展

上图所示&#xff1a;&#xff08;a&#xff09;增加台面有助于提高β-Ga2O3肖特基势垒二极管的阻断电压&#xff08;b&#xff09;。 氧气退火和自对准台面终端使β-Ga2O3二极管进一步走向商业化。 虽然β-Ga2O3电力电子技术已经取得了长足的进步&#xff0c;但仍然存在挑战&…

安卓使用so库

最近需要给小伙伴扫盲一下如何使用Android Studio 生成一个SO文件&#xff0c;网上找了很多都没有合适的样例&#xff0c;那只能自己来写一个了。 原先生成SO是一个很麻烦的事情&#xff0c;现在Android Studio帮忙做了很多的事情&#xff0c;基本只要管好自己的C代码即可。 …

QT creator qt6.0 使用msvc2019 64bit编译报错

qt creator qt6.0报错&#xff1a; D:\Qt6\6.3.0\msvc2019_64\include\QtCore\qglobal.h:123: error: C1189: #error: "Qt requires a C17 compiler, and a suitable value for __cplusplus. On MSVC, you must pass the /Zc:__cplusplus option to the compiler."…

VTK —— 三、简单操作 - 示例3 - 将点投影到平面上(附完整源码)

代码效果 本代码编译运行均在如下链接文章生成的库执行成功&#xff0c;若无VTK库则请先参考如下链接编译vtk源码&#xff1a; VTK —— 一、Windows10下编译VTK源码&#xff0c;并用Vs2017代码测试&#xff08;附编译流程、附编译好的库、vtk测试源码&#xff09; 教程描述 本…

什么是视频号小店?为什么这么多人都在做?一文带你轻松入门!

大家好&#xff0c;我是电商花花。 现在电商的快速发展&#xff0c;电商行业在各大电商平台上不断发展&#xff0c;而视频号小店也被更多人看到和入驻&#xff0c;让更多创业者对视频号小店产生兴趣。 知道的人都觉得视频号小店是一个不可多得的创业项目&#xff0c;因为这里…

rust 使用记录

rust 使用记录 安装包管理镜像源 安装 参考 rust install sudo apt install -y curl # 安装 curl --proto https --tlsv1.2 -sSf https://sh.rustup.rs | sh # 加载环境变量 source $HOME/.cargo/env # 查看版本 rustc --version rustc -V# 更新Rust rustup update# 卸载 # r…

下一代Nginx? OpenNjet 的入门实践

何为 OpenNjet &#xff1f; OpenNJet 应用引擎是基于 NGINX 的面向互联网和云原生应用提供的运行时组态服务程序&#xff0c;作为底层引擎&#xff0c;OpenNJet 实现了NGINX 云原生功能增强、安全加固和代码重构&#xff0c;利用动态加载机制可以实现不同的产品形态&#xff0…

休斯《公共管理导论》第5版/考研真题解析/章节题库

第一部分 考研真题精选 一、概念题二、简答题三、论述题四、案例分析题第二部分 章节题库 第1章 一个变革的时代第2章 政府的角色第3章 传统的公共行政模式第4章 公共管理第5章 公共政策第6章 治 理第7章 问 责第8章 利害关系人和外部环境第9章 管制、外包和公共企…