面向过程,面向对象,函数式对同一个问题的思考方式

我之所以对函数式代码感兴趣是因为函数式代码富有表现力,可以使用简短、紧凑的代码完成工作,同时能对特定的问题给出优雅的解决方案。现代的编程语言不约而同的朝着面向对象、函数式、动态、解释执行的方向发展,例如Ruby,Swift。而另一些语言则更加强调函数式编程,如F#,Scala,这种语言有着强大的类型推断系统,编写的代码洁程度则令人叹为观止。

在F#编写一个两个数相加的函数,在F# Interactive中输入:

let add num1 num2=num1*num2;;

F# Interactive为我们推断了这个函数类型:val add : num1:int -> num2:int -> int,表示add有两个int类型的参数得到了1个int类型。

函数当作参数:

        //C#
        private int Twice(int input,Func<int,int> f)
        {
            return f(f(input));
        }
        var result = Twice(2, n => n*n);

使用F#则只需要非常简洁的一个函数声明:

> let twice (input:int) f=f(f(input));;

val twice : input:int -> f:(int -> int) -> int

> twice 2 (fun n->n*n);;
val it : int = 16

val twice : input:int -> f:(int -> int) –> int 这句话则是F# Interactive给出的推断:twice函数需要一个int参数和一个(int->int)的函数作为参数,返回一个int.

这两个例子仅仅是热身,并不是本篇博客的重点,所以你觉得前两个例子很无聊或者没太看明白请继续看下面的总结。

场景:某种活动会有一个日程安排(Schedule),日程安排有3中类型,只举办一次(Once),每天一次(Daily),每周一次(Weekly)。活动会根据日程安排(Schedule)的类型不同具有不同的宣传内容,不同的延期举行策略。

你对于这样的场景会有怎么样的思考呢?

一、面向过程类型的编码方式

面向过程类型的编码是需求的直译过程,代码会写成这样:

1.显示活动的宣传内容:

        public void ShowScheduleDescriptions()
        {
            switch (ScheduleType)
            {
                case ScheduleType.Once:
                    Console.WriteLine("this is once activity");
                    break;
                case ScheduleType.Daily:
                    Console.WriteLine("this is daily activity");
                    break;
                case ScheduleType.Weekly:
                    Console.WriteLine("this is weekly activity");
                    break;
                default:
                    throw new InvalidOperationException("unsupported schedule");
            }
        }

这样的代码初次看起来没什么问题,实际存在两个危险信号:

  • 违反开放封闭(OCP)原则,如果有一天需要加入一种Monthly类型,无疑需要修改这个方法;
  • 这样的代码风格会让接下来的开发者不假思索的进行延续,比方说需要根据不同的活动类型延期活动;

2. 延期活动:

        public void DelaySchedule()
        {
            switch (ScheduleType)
            {
                case ScheduleType.Once:
                    Console.WriteLine("Delay one hour");
                    break;
                case ScheduleType.Daily:
                    Console.WriteLine("Delay one day");
                    break;
                case ScheduleType.Weekly:
                    Console.WriteLine("Delay one week");
                    break;
                default:
                    throw new InvalidOperationException("unsupported schedule");
            }
        }

这样的代格违反了DRY原则,相同的代码框架却无法重用。

二、面向对象的编码方式

对于一个有经验的OO开发者,一旦看到switch,if(type=typeof(…))之类的代码马上会提高警惕,是不是有一些抽象类型没有被找出来?在这个例子中则会找出下面的抽象:

    public  class Schedule
    {
        public virtual void ShowShowScheduleDescriptions()
        {
        }

        public virtual void DelaySchedule()
        {
        }
    }

    public class OnceSchedule : Schedule
    {
        public override void ShowShowScheduleDescriptions()
        {
            Console.WriteLine("this is once activity");
        }

        public override void DelaySchedule()
        {
            Console.WriteLine("Delay one hour");
        }
    }

    public class DailySchedule : Schedule
    {
        public override void ShowShowScheduleDescriptions()
        {
            Console.WriteLine("this is daily activity");
        }

        public override void DelaySchedule()
        {
            Console.WriteLine("Delay daily day");
        }
    }

    //... other schedule

这样的代码很好的解决了面向过程代码的两个问题,看起来更加具有扩展性,随着新类型的Schedule引入,旧的代码完全不用改动。

当然事情也不是绝对的,什么情况下需要改动旧代码呢?当需要扩展Schedule的行为的时候,例如需求升级,不同的Schedule具有不同的举办方式,我们不得不在每种Schedule中加入一个 void Hold()方法。

三、函数式解决方案

函数式语言则使用可区分联合和模式匹配来处理此类问题。

定义一个Schedule可区分联合:

type Schedule=
| Once of DateTime
| Daily of DateTime*int
| Weekly of DateTime*int

这个类型既说明了Schedule有三个不同的类型,同时定义了三种类型分别具有的数据结构。像是Enum和类的综合体,但是又显得特别精致。

1.显示活动的宣传内容,使用了模式匹配:

let ShowShowScheduleDescriptions schedule=
match schedule with
| Once(DateTime)-> printfn "this is once activity"
| Daily(DateTime,int)->printfn "this is daily activity"
| Weekly(DateTime,int)->printfn "this is weekly activity"

这个方法类似于switch…case,但是通过匹配可区分联合来实现,而不是通过一个显示的Enum来实现。

2. 延期活动:

let DelaySchedule schedule=
match schedule with
| Once(DateTime)-> printfn "Delay one hour"
| Daily(DateTime,int)->printfn "Delay one day"
| Weekly(DateTime,int)->printfn "Delay one week"

函数式编程的解决方案认为可以很方便的添加新的行为,例如增加新的行为:Hold()。通过定义可区分联合和模式匹配来完成编码,整个解决方案像是面向过程和面向对象的一种结合体,但是侧重点不同,实现的代码也更加精致。

时间: 2024-12-21 18:40:40

面向过程,面向对象,函数式对同一个问题的思考方式的相关文章

07-09 面向过程与函数式

[TOC] 一 编程范式 ? 很多初学者在了解了一门编程语言的基本语法和使用之后,面对一个'开发需求'时仍然会觉得无从下手.没有思路/套路,本节主题"编程范式"正是为了解决该问题,那到底什么是编程范式呢? 编程范式指的就是编程的套路,打个比方,如果把编程的过程比喻为练习武功,那编程范式指的就是武林中的各种流派,而在编程的世界里常见的流派有:面向过程.函数式.面向对象等,本节我们主要介绍前两者. ? 在正式介绍前,我们需要强调:"功夫的流派没有高低之分,只有习武的人才有高低之分

php连接数据库的两种方式- 面向过程 面向对象

一.面向对象1. 链接数据库 $conn = @new mysqli("127.0.0.1","root","","mydb"); if($conn->connect_errno){ //返回链接错误号 // 返回链接错误信息 die("数据库链接失败:".$conn->connect_error); } 2. 选择数据库 $conn->select_db("mydb"

面向过程—面向对象(C++的封装,this)_内存四区_变量生命周期

1.面向对象主要涉及  构造函数.析构函数.虚函数.继承.多态等. 2.对各种支持 的底层实现机制 c语言中,数据 和 处理数据的操作(函数) 是分开来声明,即语言本身并没有支持 “数据和函数”的关联性. 在C++中,通过抽象数据类型(abstract data type, ADT),在类中定义数据和函数,来实现数据和函数直接的绑定. C++成员数据:static.nonstatic C++成员函数:static.nonstatic.virtual C++中的类class从面向对象理论出发,将变

2017 5 31 php面向过程 面向对象1

面向过程的语法定义变量:定义函数:使用变量(输出,赋值,等)调用函数:流程控制(if,switch,for,while等) 面向对象的语法1,定义类:定义类的语法中,只有这3种代码:1.1定义属性(变量)1.2定义方法(函数)1.3定义常量(类常量)2,创建类的对象:3,使用对象:使用对象也几乎只有3个方式:3.1使用其属性:因为属性就是"变量",则使用其属性,也就是跟以前使用变量一样.3.2使用其方法:因为方法就是"函数",则使用其方法,也就是跟以前使用函数一样.

C++中静态成员变量和静态成员函数(面向过程&amp;&amp;面向对象)

数据成员可以分静态变量.非静态变量两种. 静态成员:静态类中的成员加入static修饰符,即是静态成员.可以直接使用类名+静态成员名访问此静态成员,因为静态          成员存在于内存,非静态成员需要实例化才会分配内存,所以静态成员不能访问非静态的成员..因为静态成员  存在于内存,所以非静态成员可以直接访问类中静态的成员. 非成静态员:所有没有加Static的成员都是非静态成员,当类被实例化之后,可以通过实例化的类名进行访问..非静态成             员的生存期决定于该类的生存

python面向过程与函数式编程

周六闲暇的午后,看到博客园众多大神的技术贴.作为一个什么都不懂的小学生,也开通了自己的博客,以后可以对外装×成伪大神了.第一篇记录下今天下午学的python基础: 1.面向过程编程:在python中,所说的过程其实和函数差别不大,也需要def进行定义,但是过程是没有返回值的. def guocheng(): print('我是过程') 上面定义的就是一个过程,没有返回值,只有函数内部的相关逻辑. 调用上面的过程:a=guocheng(),这样即可调用,如果在面板上打印a,会显示NONE,因为过程

面向过程&amp;面向对象

编程范式 编程是程序员用特定的语法+数据结构+算法组成的代码来告诉计算机如何执行任务的过程,一个程序是程序员为了得到一个任务结果而编写的一组指令的集合,正所谓条条大路通罗马,实现一个任务的方式有很多种不同的方式,对这些不同的编程方式的特点进行归纳总结得出来的编程方式类别,即为编程范式. 不同的编程范式本质上代表对各种类型的任务采取的不同的解决问题的思路, 两种最重要的编程范式分别是面向过程编程和面向对象编程. 原文地址:https://www.cnblogs.com/xiugeng/p/8667

面向对象和面向过程的编程方式的理解

面向对象和面向过程的区别? 如果说面向对象和面向过程的具体区别,最深入的地方应该是去看设计模式,推荐大话设计模式那本书,讲的比较好.本人只不过简单叙述下,重点是如何进行面向对象和面向过程的编程,只有会编程了,才能真正懂得面向对象和面向过程的区别.否则都是纸上谈兵. 面向过程:是以计算机线性思维的方式进行编程.一步一个脚印的执行.本身也没有问题,但是如果遇到需求多变的情况,或者功能的添加和删除,将极其影响原来的程序代码,必须要重写或者修改,或者重新组织原来的代码. 面向对象:在对需求多变的时候,不

o&#39;c基础第一天面向过程与面向对象

1. OC将C的复杂的东西简单 a. #import 指令. b. NSLog函数. c. NSString d. BOOL 2. OC在C的基础之上增加了一些面向对象的语法. 面向过程 面向对象. 是解决问题的不同的思路. 1). 将大象放进冰箱. a. 打开冰箱门. b. 把大象放进冰箱 c. 把冰箱门关上. 面向对象. 找到1个冰箱. 只要这个冰箱有自动开门 自动拉近大象 自动关门. 2). 买电脑的需求 a. 根据自己的预算和需求确定型号. 查找资料. b, rMBP 9288 c, 到