面向对象思想以及结构化编程思想和golang面向接口思想

golang是一门全新的语言,比其他目前主流语言都新,2009年后公开,相比其他语言更是面向了当前网络化编程和未来智能编程,例如在摩尔定理的逐渐失效问题,所以其有非常明显的特点:面向接口、高并发goroutine(CSP)、易于使用、数据结构丰富、自有gcc。
故而,搞清楚golang的设计思想和重要优缺点是成为一个高级程序工程师必不可少的必经之路。由此,本文主要述说面向对象设计思想、结构化设计思想和面向接口设计思想的异同,使在实际开发程序时和、解决问题时,能更清醒深刻的解决问题。
面向结构、面向对象之异同
  • 软件工程实际是解决软件开发和软件设计的认识论和方法论,目的是解决软件开发中的实际问题。软件工程实际又分为两个主要软件设计思想:结构化设计(结构化方法包括结构化分析(Structured Analysis,简称SA)、结构化设计(Structured Design,简称SD)和结构化程序设计(Structured Program Design,简称SP)三部分内容。),另外,面向对象设计(面向对象方法包括面向对象分析(Object-Oriented Analysis,简称OOA)、面向对象设计(Object—Oriented Design,简称OOD)和面向对象程序语言(Object-Oriented Program Design,简称OOP)。),这两个实际代表了软件开发领域的不同模式。
  • 起源上:来自于程序结构理论》和《GOTO陈述有害论》的提出,证明了任何程序的逻辑结构都可以用顺序结构、选择结构和循环结构来表示,确立了结构化程序设计思想。
    • 结构化方法把对程序的分析、设计,延伸至对项目工程的分析、设计,结合程序设计语言的技术支持,得以产生和发展。
    • 20世纪80年代,随着应用系统的日趋复杂、庞大,结构化开发方法在工程应用中出现了一些问题。同期,面向对象程序设计思想经过20年的研究和发展逐渐成熟,一大批面向对象语言相继出现,面向对象方法自产生就广受青睐。90年代中期,互联网兴起,JAVA语言因跨平台特性得以蓬勃发展;21世纪初,不受限于时空的联合开发成为常态;今天,移动APP市场火爆,Andriod开发成为热点。面向对象方法已经成为软件开发方法的中坚力量。
  • 思想上:结构化方法承袭了结构化程序设计的思想,把待解决的问题看作一个系统,用系统科学的思想方法来分析和解决问题。结构化方法遵循抽象原则、分解原则和模块化原则;以数据和功能为中心;以模块为基本单位;以算法为程序核心;强调逐步求精和信息隐藏。面向对象方法的思想是模拟了客观世界的事物以及事物之间的联系。面向对象以类取代模块为基本单位;通过封装、继承和多态的机制,表征对象的数据和功能、联系和通信;通过对对象的管理和对象间的通讯完成信息处理与信息管理的计算和存储,实现软件功能。
    • 对于结构化方法,模块由函数实现,完成对输入数据的加工和计算,数据和功能是分离的;而面向对象把数据和功能封装在对象中,形成一个整体。两种方法在数据和功能上的不同处理是其思想上的本质差别。
  • 分析上:
    • 建立模型是为了更好地理解要模拟的现实世界,是软件开发方法的核心问题。在结构化方法中,使用SA构建系统的环境模型和逻辑模型,实现模型的主要工具有数据字典(DD)、ER图和数据流图(DFD)。数据字典是一个包含所有系统数据元素定义的仓库;ER图描述了数据之间的属性及联系;数据流图是描述信息流和数据从输入到输出变换,并展示系统和外部的接口、数据的输入和输出以及数据的存储的应用图形技术。SA的前提条件是需求分析,建模过程是迭代分解需求、不断细化应用的过程,即数据流图的分解从顶层图开始,按照每个加工对应一个子图的分解原则,逐层分解为0层图、1层图等。
    • 面向对象方法使用OOA定义类,对现实世界建模。OOA的主要任务是要在问题域上构建具有主题层、对象层、结构层、属性层和服务层的OOA模型,实现模型的主要工具有用例图(Use-Case)和类图(Class Diagram)。用例图从用户角度描述系统功能,并指出各功能的操作者,是对需求分析的整理;类图定义了类的组成(属性和服务)、类的结构和类间的关系,确定并划分系统中的类。经过OOA,系统的静态模型建立起来。相对于结构化方法使用DD、ER图和DFD分别描述数据和功能(尽管二者存在相互参考),面向对象方法中,无论是用例图还是类图,数据和功能的描述总是并行的。
  • 设计上:
    • 在结构化方法中,使用SD构建系统的行为和功能模型,实现模型的主要工具有模块结构图(SC)和程序流程图。模块结构图说明了系统的模块的划分、模块的功能、模块间的数据传递及调用关系。根据数据流图,我们能够映射出相应的软件的上层模块结构;结合数据流图,我们可以逐步分解上层模块,设计出中、下层模块;对于得到的全部模块,我们需要设计模块基本的内部结构和外部接口及对模块结构进行优化。进一步,则是针对每一个模块设计程序流程图,整理优化,归纳算法。SD依然是对项目系统的进一步分解求精的过程,把模型从逻辑级,细化到模块级,再细化到程序级。
    • 而OOD不只是对OOA的细化,更主要的,构建了系统的动态模型,实现模型的主要工具有交互图(Sequence Diagram)、状态图(State Diagram)、活动图(Activity Diagram)。和模块相比,对象最大的不同是具有“活性”,突出表现在对象具有状态和对象间能够通讯。交互图描述对象间的交互关系,显示对象之间的动态合作关系,强调对象之间消息发送的时间顺序;状态图描述对象的所有可能状态,以及事件发生时状态的转移条件;活动图描述为满足用例要求所进行的活动以及活动间的约束关系,用于识别并行活动,以提高系统效率。
    • 从设计方面,我们可以比较明显地看出结构化和面向对象的区别。结构化方法的核心是程序,从分析到设计,其实是从抽象到具体,从模糊到清晰地实现程序的过程;而面向对象方法的核心是功能,分析的是对象,设计的是行为,程序设计和系统设计相对分离
  • 程序设计上:
  • 以例子进行说明(银行存取款)
//结构化程序设计
int main () {
    int count;
    int money;
    int type;
    scanf (“%d %d %d”, &count, &money, &type);
    if (type)
        printf (“%d”, count – money);
    else
        printf (“%d”, count + money);
}
//面向对象程序设计
class Count {
    int count;
    Count (int count) {
        this.count = count;
    }
    int save (int money) {
        count += money;
    }
    int take (int money) {
        if(count >= money)
            count -= money;
    }
}

  • 从上例可见,结构化程序设计是一种过程式的“解题”的方式,程序关注且只关注对于输入数据,输出正确的结果,代码是算法的直接体现,代码效率高;面型对象程序设计是整体式的“建模”的方式,程序关注现实客体,而非某些数据,代码是功能的直接体现,复杂的算法往往是一两行库函数处理,代码效率低。
  • 扩展重用上:
    • 结构化方法是面向整体应用进行的分析、设计,程序设计也是过程式的针对固定的输入域,代码定向性明显。所以,结构化方法的可扩展性较差,功能的变化可能危及整个系统;重用性不好,若系统间存在嵌套关系,主系统可重用子系统;较难以组合拼接,系统的设计实现是紧耦合的,连接往往是有缝的。
    • 相反,面向对象方法虽然基于应用,但面向现实客体,对象之间独立性较强,功能是对象的交互。所以,面向对象的可扩展性较强,只需扩展或修改某个类,或调整某种通讯;重用性好,面向对象的继承和多态机制大大提高了代码重用的层次和粒度;易于组合拼接,对象是数据和功能的最小单位,为对象建立新的通信的联系,就能够组合出新的软件系统。
  • 应用上:
    • 结构化方法的实质是问题求解,结构化程序是由算法决定的,算法是程序员分析设计的,程序的执行过程主要是由程序员控制,而不是由用户控制;面向对象方法中,程序员设计的是对象属性及操作方法,但在什么时间、使用什么方式操作对象则是完全由用户交互控制。
    • 结构化方法的建模工具难以表达交互性强的软件系统,程序设计融入系统的分析和设计中,处理大型系统时会过于复杂,甚至很难控制;面向对象方法的抽象机制提供了自然的建模方法,特别是能很好地把握对象之间复杂的相互关系。
    • 结构化方法比较适合工程计算、实时数据的跟踪处理、各种自动控制系统等等; 面向对象分析更加适用于复杂的、由用户控制程序执行过程的应用软件,比如大型游戏软件以及各类管理信息系统软件[3]。
  • 二者之结合上:
    • 经过上述分析,我们可知结构化方法和面向对象方法对于不同的软件系统各有优劣。结构化方法把解空间分数据和功能两部分,可以更加清晰地进行需求分析和功能分解,数据流图能够细致地说明数据在各个功能模块之间的流动和变化,更适于系统设计的前期阶段。设计人员清楚地了解数据和系统要求的操作后,面向对象方法能够把数据和功能以对象为单位封装成一个整体,更直观地表达对象的状态变化和对象间的交互,更加准确地分析功能的实现过程,更适于在软件后期细化系统的具体行为。基于此,设计的混合式软件开发方法如下:
        1) 使用SA进行需求分析,建立数据字典,构建总的和分层的数据流图。
        2) 使用模块结构图设计系统的独立功能块,做出模块内的程序流图。
        3) 结合数据流图,聚合同类模块,规约类,根据程序流图,设计类的属性和类的方法。
        4) 使用OOD建立系统的动态模型,分析对象的行为和协作。
        5) 总体面向对象程序设计,细节结构化程序设计优化,实现代码层。
        使用混合式方法,我们能够充分利用两种方法的优点,扬长避短,提高开发的效果和效率。
        无论是结构化方法,还是面向对象方法,都是用来解决日益矛盾的软件危机的系统方法。从直接开发,到结构化方法,再到面向对象方法,软件构件的愈发独立、可重用,开发在一个更高的层次进行,分析层、设计层和代码层关联性减少。这些都有利于系统开发员更加关注功能本身,提高软件质量。硬件性能的提高会使计算机的使用越发广泛,软件工作的环境更加复杂,软件的功能更加丰富,软件的性能更需提高,对软件开发方法提出了更多的要求,会涌现更高层次的新的方法。无论使用哪种开发方法,或者是混合哪几种开发方法,我们都要因地制宜,依据需求分析和系统要求,做出最好的选择或组合。
Golang面向对象和接口编程
  • 面向对象
    • 概念
      早期编程是面向过程的,比如C语言。面向过程编程在构造系统时,无法解决重用,维护,扩展的问题,而且逻辑过于复杂,代码晦涩难懂,因此产生了面向对象编程思想:把构成问题的各个事物分解成各个对象,对象作为程序的基本单位,将程序和数据封装其中,以提高程序的重用性,灵活性和可扩展性。(封装、继承、多态)
type Node struct {
        Value int
        Left  *Node
        Right *Node
}
func (node *Node) SetValue(value int) {
        node.Value = value
}
func (node *Node) Traverse() {
        if node == nil {
                return
        }
        node.Left.Traverse()
        node.Print()
        node.Right.Traverse()
}
func (node *Node) Print() {
        fmt.Print(node.Value, ” “)
}
  • 说明几个地方:
    • 结构体内只定义属性,方法则是定义在结构体外的
    • GO没有构造函数,一般通过工厂函数来创建返回对象
      上述*Node为receiver,接收者, 它既可以传值也可以传指针;一般情况下,它的类型应该统一,当需要改变结构体内容的时候或者结构体很大时,需要传递指针。如果接收者为指针,也可以通过值对象访问,GO会自动取其地址, 反之则不行.nil指针也可以调用方法,某些情况下需要特殊处理。首字母大写: public;首字母小写:private (针对包范围)
对象初始化
var root tree.Node
root.SetValue(8)
root.Left = &tree.Node{}
root.Right = &tree.Node{5, nil, nil}
root.Right.Left = new(tree.Node)
root.Left.Right = new(tree.Node)
root.Left.Right.SetValue(6)
root.Right.Left.SetValue(4)
root.Traverse() // 0,6,8,4,5
  • 扩展已有类型
    由于在Golang中,为结构体创建的方法必须在一个保内,且对象不支持继承。但它提供了两种方法来扩充系统类型或者别人的类型:定义别名;使用组合。
定义别名
在Slice的基础上实现队列。
package queue
type Queue []interface{}
func (q *Queue) Push(obj interface{}) {
        *q = append(*q, obj)
}
func (q *Queue) Pop() interface{} {
        if q.IsEmpty() {
                return nil
        }
        head := (*q)[0]
        *q = (*q)[1:]
        return head
}
func (q *Queue) IsEmpty() bool {
        return len(*q) <= 0
}
func main() {
        queue := Queue{}
        queue.Push(“Hello”)
        queue.Push(1)
        queue.Push(1.5)
        queue.Push(true)
        fmt.Println(queue.Pop())
        fmt.Println(queue.Pop())
        fmt.Println(queue.IsEmpty())
        fmt.Println(queue.Pop())
        fmt.Println(queue.Pop())
        fmt.Println(queue.IsEmpty())
}
  • 使用组合
// 组合方式扩展
type myNode struct {
        node *tree.Node
}
// 扩展:前序遍历
func (node *myNode) preOrder() {
        if node == nil || node.node == nil {
                return
        }
        node.node.Print()
        left := myNode{node.node.Left}
        right := myNode{node.node.Right}
        left.preOrder()
        right.preOrder()
}
  • 继承(Composition)
    之前也说过,Golang中不支持继承,但是提供了Composition。
Golang中的Compostion有两种形式, 匿名组合(Pseudo is-a)和非匿名组合(has-a)。
  • 匿名组合
type Human struct {
        Name string
        Age  int
}
func (Human) Speak() {
        fmt.Println(“Hello!”)
}
type Teacher struct {
        Human
        Name    string
        School  string
        Subject string
}
func (t Teacher) Speak() {
        fmt.Printf(“My name is %s, I teach %s”, t.Name, t.Subject)
}
func main() {
        t := Teacher{Human: Human{
                “Bob”,
                18,
        },
                Name:    “John”,
                School:  “MIT”,
                Subject: “CS”,
        }
        // My name is John, I teach CS
        t.Speak()
}
  • 非匿名组合
type Student struct {
    h      Human //非匿名字段
    school string
}
  • 面向接口
    • 接口的定义和实现
      Golang不同于其他语言,接口是由使用者定义,而实现是隐式的, 只需实现接口中定义的方法即可。
  • 接口组合
type Reader interface {
    Read(p []byte) (n int, err error)
}
type Writer interface {
    Write(p []byte) (n int, err error)
}
type ReadWriter interface {
    Reader
    Writer
}
综上,实际可以看出来golang是一种全新的语言,综合了各种编程语言特点、网络化场景以及数据化、智能化、物联网化的未来特征,兼顾编程便宜性,而产生的新语言,其可以更加灵活、编辑、易用,非常适合作为一个新的突破能力。

发表评论

电子邮件地址不会被公开。 必填项已用*标注