美文网首页
简谈面向对象(待更新

简谈面向对象(待更新

作者: 伽马星人 | 来源:发表于2017-09-19 22:52 被阅读367次

    -背景-


    因为最早是搞NOI什么的,所以没有接触过任何关于软件设计的知识,所以更不懂什么设计典范,标准什么的。

    (我记得我刚开始搞竞赛的时候代码是左对齐的。每次写一会代码就要数数现在是第几个begin end。编一段程序开始时先定义一遍a b c d... z变量,不够就aa bb... 搞得和excel一样。逃

    到了大学,加入了学校的一个以移动开发为方向的工作室(大爱!)。然后遇到了带我入门学长!(超级感谢他!他超超超牛逼!)然后他每周都会给我讲讲设计规范、项目什么的,一讲就是几个小时,有时候我都累了,他还乐此不疲的讲讲讲。从此就开启了我漫长的OC道路。

    (对了,也是他叫我写写技术博客的。就当锻炼我的文笔了(捂脸

    -正文-


    我们先来看一下维基百科上对面向对象的定义

    面向对象程序设计(英语:Object-oriented programming,缩写:OOP)是种具有对象概念的程序编程范型,同时也是一种程序开发的抽象方针。它可能包含数据、属性、代码与方法。对象则指的是类的实例。它将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的重用性、灵活性和扩展性,对象里的程序可以访问及经常修改对象相关连的数据。在面向对象程序编程里,计算机程序会被设计成彼此相关的对象。

    做过算法竞赛的人都知道,一个好的代码一般都是一个函数一个函数堆出来的,而且恨不得main函数中就只有一堆函数名。那时还不知道这是面向过程编程,以为编程只有这种形式。

    面向过程是先分析过程,然后再把这些过程一个一个写成函数调用,数据为函数服务。就像有的人像做数学题一样,第一步求一些东西,第二步再求一些东西,第三步......最终一步步把题目做出来,每一个函数都是一个很完整的过程,里面会处理一大堆东西,计算一堆东西,然后创建不同的函数来干不同的事情,但是他们都是一步步做下去,数据的作用就是让函数调用的。

    但是这有一个问题,在一个项目中,会经常出现要改一些东西,而面向过程这种设计模式改起来要很麻烦,要改一堆东西,很难去维护一个项目。

    于是很自然的就引出了面向对象的概念,以一个对象为中心,各种函数为它服务,它是按照功能来进行划分的。一个大的机器被分成很多部分,然后每个部分都是一个对象,有自己的构成元素方法。这样的话,以后要改哪个部分,就只要改那个部分了,不用把整个都改个遍。

    当然缺点也还是有的(为了OOP而OOP算不算。。)
    总结了知乎大佬Milo Yip的话,就是以下几个观点:

    现在的OOP有可能不缓存友好(cache friendly)

    1. 过度封装:使用OOP时,会把一些复杂的问题拆分抽象成为较简单的独立对象,通过对象的互相调用去实现方案。但是,由于对象包含自己封装的数据,一个问题的数据集会被分散在不同的内存区域。互相调用时很可能会出现数据cache miss的情况。
    2. 多态:一般多态实现中,会使用到虚函数表。虚函数表是通过加入一次间接来实现动态派送。但在调用的时候需要读取虚函数表,增加cache miss的情况。但如果类的数目极多,把函数指针如果和数据放在一起有时候可放缓问题。
    3. 数据分布:虽然OOP本身并无限制数据的布局方式,但是基本上绝大部分OOP语言都是把成员变量连续包裹在一段内存中。(甚至连C都要放在一个struct中)在OOP中,通过封装,一个类的各种功能会被实现为多个成员函数,而每个成员函数可能只会存取极少量的成员变量。于是存储其中几个成员变量时,其它成员变量也会载入缓存造成浪费。在传统的OOP编程范式及实现方法,数据布局的问题几乎没法解决。

    简单的举个面向对象的例子,比如,现在我要获得水饺这个对象(最近最佳团日刚组织了“包饺子”活动 虽然我因为要建模没去...)。
    饺子有两个东西:饺子皮和饺子馅,于是我们创造了这两个对象

    • 饺子皮
    #import <Foundation/Foundation.h>
    
    @interface DumplingWrapper : NSObject
    {
    //构成的元素(自身拥有的一些东西
        NSNumber *whiteLevel; //1. 雪白程度(这。算一个参数吧
        NSNumber *radius; //2. 半径
        NSNumber *tasteLevel; //3. 口感
    }
    
    //方法(对自己的属性的一些操作
    - (NSNumber *)whiteLevel; //1. 获取饺子皮雪白程度(get方法
    - (void)setWhiteLevel:(NSNumber *)myWhiteLevel; //2. 设置饺子皮雪白程度(set方法
    
    //以下是各种set、get方法
    - (NSNumber *)radius;
    - (void)setRadius:(NSNumber *)myRadius;
    - (NSNumber *)tasteLevel;
    - (void)setTasteLevel:(NSNumber *)myTasteLevel;
    - (void)touch; //3. 摸(不是膜)一下这张皮(不要和我说你拿到饺子皮 不会摸一下!
    @end
    

    尴尬。我真的不知道能对饺子皮做些什么。除了摸一下。然后下面是方法的具体实现

    #import "DumplingWrapper.h"
    
    @interface DumplingWrapper()
    @end
    
    @implementation DumplingWrapper
    - (instancetype)init {
        self = [super init];
        if (self) {
            whiteLevel = [[NSNumber alloc] initWithInt:5];
            radius = [[NSNumber alloc] initWithFloat:4.0];
            tasteLevel = [[NSNumber alloc] initWithInt:6];
        }
        return self;
    }
    
    - (void)touch {
        NSLog(@"%@",@"你碰了一下他");
    }
    
    - (NSNumber *)whiteLevel {
        return whiteLevel;
    }
    
    - (void)setWhiteLevel:(NSNumber *)myWhiteLevel {
        whiteLevel = myWhiteLevel;
    }
    
    - (NSNumber *)radius {
        return radius;
    }
    
    - (void)setRadius:(NSNumber *)myRadius {
        radius = myRadius;
    }
    
    - (NSNumber *)tasteLevel {
        return tasteLevel;
    }
    
    - (void)setTasteLevel:(NSNumber *)myTasteLevel {
        tasteLevel = myTasteLevel;
    }
    @end
    
    
    • 饺子馅
    #import <Foundation/Foundation.h>
    
    @interface DumplingStuffing : NSObject
    {
    //构成的元素
        NSArray<NSString *> *stuffing; //1. 有什么馅料
        NSNumber *mass;//2. 馅料的质量
    }
    
    //方法
    //一堆set、get方法
    - (NSArray *)stuffing;
    - (void)setStuffing:(NSArray *)myStuffing;
    - (NSNumber *)mass;
    - (void)setMass:(NSNumber *)myMass;
    - (void)addMass:(NSNumber *)addedMass; //1. 增加点馅料
    - (void)chopStuffing; //2. 把馅料剁剁剁剁剁
    @end
    

    方法的具体实现是

    #import "DumplingStuffing.h"
    
    @interface DumplingStuffing()
    @end
    
    @implementation DumplingStuffing
    - (instancetype)init {
        self = [super init];
        if (self) {
            stuffing = [[NSArray alloc] initWithObjects:@"荠菜",@"猪肉",@"姜", nil];
            mass = [[NSNumber alloc] initWithFloat:100];
        }
        return self;
    }
    
    - (void)chopStuffing {
        NSLog(@"%@",@"馅料已经被你剁的粉碎");
    }
    
    - (NSArray *)stuffing {
        return stuffing;
    }
    
    - (void)setStuffing:(NSArray *)myStuffing {
        stuffing = myStuffing;
    }
    
    - (NSNumber *)mass {
        return mass;
    }
    
    - (void)setMass:(NSNumber *)myMass {
        mass = myMass;
    }
    
    - (void)addMass:(NSNumber *)addedMass {
        mass = [NSNumber numberWithFloat:[mass floatValue] + [addedMass floatValue]];
    }
    @end
    

    然后饺子自己本身也是一个对象,它拥有饺子皮和饺子馅这两个对象,当然它也有一些它自己的构成元素方法

    #import <Foundation/Foundation.h>
    #import "DumplingWrapper.h"
    #import "DumplingStuffing.h"
    
    @interface Dumpling : NSObject
    {
    //构成的元素
    DumplingWrapper *dumplingWrapper; //1. 饺子皮
    DumplingStuffing *dumplingStuffing; //2. 饺子馅
    NSNumber *faceScore; //3. 饺子的颜值
    }
    
    //方法
    //还是一堆get、set方法(是不是很麻烦,其实可以@property来代替,但是第一次还是写的详细一点
    - (DumplingWrapper *)dumplingWrapper;
    - (void)setDumplingWrapper:(DumplingWrapper *)myDumplingWrapper;
    - (DumplingStuffing *)dumplingStuffing;
    - (void)setDumplingStuffing:(DumplingStuffing *)myDumplingStuffing;
    - (void)makeDumpling; //1. 包饺子
    - (void)cookDumpling; //2. 煮饺子
    @end
    

    下面是方法的具体实现

    #import "Dumpling.h"
    
    @interface Dumpling()
    @end
    
    @implementation Dumpling
    - (instancetype)init {
        self = [super init];
        if (self) {
            dumplingStuffing = [[DumplingStuffing alloc] init];
            dumplingWrapper = [[DumplingWrapper alloc] init];
            faceScore = [[NSNumber alloc] initWithFloat:10];
        }
        return self;
    }
    - (void)makeDumpling {
        NSLog(@"%@", @"哇!你包了一个饺子");
    }
    - (void)cookDumpling {
        NSLog(@"%@", @"哇!你煮了一个饺子");
    }
    - (DumplingWrapper *)dumplingWrapper {
        return dumplingWrapper;
    }
    - (void)setDumplingWrapper:(DumplingWrapper *)myDumplingWrapper {
        dumplingWrapper = myDumplingWrapper;
    }
    - (DumplingStuffing *)dumplingStuffing {
        return dumplingStuffing;
    }
    - (void)setDumplingStuffing:(DumplingStuffing *)myDumplingStuffing {
        dumplingStuffing = myDumplingStuffing;
    }
    @end
    

    对象Dumpling和对象DumplingWrapper和DumplingStuffing的关系是“我拥有你”,也就是复合关系,一般处理对象关系的时候,最重要的右两个复合继承复合的思想就是“我拥有你”,继承的思想是“我是你”。这个也不是这篇文章讨论的重点,有兴趣的小伙伴可以点击下面几个链接看具体的说明 继承(维基百科) 继承(百度百科)

    诶。复合这个概念竟然没有单独的词条。那我就给一个《Objective-C基础教程(第二版) Scott Knaster著》上的定义:

    将多个组件组合在一起,配合使用,从而得到完整的作品。

    其实从上面的例子看的出来,在OOP中,关注的重点已经从函数编程数据了。数据间通过间接方式来引用代码,这些代码可以对数据进行操作。现在煮个饺子什么的都不是叫外面的人来做了,Dumpling的实例可以自己调用自己的cookDumpling来煮,也就是说饺子自己煮!是不是很有意思!

    面向对象并不是面向过程的升级版,它们之间都各自有优点缺点,这要看干的事情是啥。

    -闲话-


    由于首次写这种技术文章,用的都是零碎时间写的,可能写的有点匆忙,有错的地方欢迎指出!此文中的很多概念并没有给出明确定义,因为写的是一些我能想到的关于面向对象的东西,并不是面向对象的详细教程。不过不用@property真的写的很难受(逃

    相关文章

      网友评论

          本文标题:简谈面向对象(待更新

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