美文网首页我爱编程
移动端常用设计模式浅析

移动端常用设计模式浅析

作者: nero_i | 来源:发表于2018-01-30 17:06 被阅读31次

    1.单例模式(Singleton Pattern)

    定义:Ensure a class has only one instance, and provide a global point of access to it.(确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。)

    OC 通用代码:

    +(GenericPlayer *)sharedInstance {
        static dispatch_once_t onceQueue;
        static GenericPlayer *instance = nil;
        dispatch_once(&onceQueue, ^{
             instance = [[self alloc] init];
        });
        return instance;
    }
    

    Swift 通用代码:

    static let shareHelper = AJDebugManager()
    

    使用场景:

    在 Cocoa Touch 框架中,最常见的使用了单例模式的就是 UIApplication 类了。每个应用程序有且仅有一个 UIApplication 的实例,它由 UIApplicationMain 函数在程序启动时创建为单例对象,之后,对同一 UIApplication 实例可以通过其 sharedApplication 类方法进行访问。

    单例用来集中管理对类的对象所提供的资源,例如应用程序中需要用集中式的类来协调其服务,这个类就应该生成单一的实例。

    单例模式在多线程的应用场合下必须小心使用。如果当唯一实例尚未创建时,有两个线程同时调用创建方法,那么它们同时没有检测到唯一实例的存在,从而同时各自创建了一个实例,这样就有两个实例被构造出来,从而违反了单例模式中实例唯一的原则。 解决这个问题的办法是为指示类是否已经实例化的变量提供一个互斥锁。

    2.工厂模式

    定义:Define an interface for creating an object,but let subclasses decide which class to instantiate.Factory Method lets a class defer instantiation to subclasses.(定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。)

    创建对象的时候,我们一般是alloc一个对象,如果需要创建100个这样的对象,如果是在一个for循环中还好说,直接一句alloc就行了,但是事实并不那么如意,我们可能会在不同的地方去创建这个对象,那么我们可能需要写100句alloc 了,但是如果我们在创建对象的时候,需要在这些对象创建完之后,为它的一个属性添加一个固定的值,比方说都是某某学校的学生,那么可能有需要多些100行重复的代码了,那么,如果写一个-(void)createObj方法,把创建对象和学校属性写在这个方法里边,那么就是会省事很多,也就是说我们可以alloc 创建对象封装到一个方法里边,直接调用这个方法就可以了,这就是简单工厂方法

    代码结构如下

    Animal 类
    
    @interface Animal :NSObject
    
    @proterty(nonatomic,copy) NSString *name;
    
    -(void)laugh;
    
    @end
    

    Dog类

    @interface Dog:Animal
    
    @end
    

    Cat类

    @interface Cat:Animal
    
    @end
    

    创建对象的工厂类

    .h
    
    @interface AnimalFactory:NSObject
    
    +(Dog *)createDog;
    
    +(Cat *)createCat;
    
    @end
    
    .m
    
    @implementation AnimalFactory
    
    +(Dog *)createDog{
    
        Dog *dog=[[Dog alloc]init];
    
        dog.name=@“baby”;
    
        return dog;
    
    }
    
    +(Cat *) createCat{
    
        Cat *cat=[[Cat alloc]init];
    
        return cat;
    }
    

    Main.m文件

    Dog *dog=[AnimalFactory createDog];
    
    Cat *cat=[AnimalFactory createCat];
    

    这是简单工厂模式

    现在创建100个Dog对象,如果这100个对象写在程序中的不同地方,按上边的方法是需要把Dog *dog=[AnimalFactory createDog];这一句话写在程序中很多不同的地方,那么现在有一个需求,就是如果需要把这些创建的100个Dog对象全部变成Cat对象,那么按照刚才的那个做法,就需要在这100句代码中把createDog方法变成createCat方法了,这样做还是很复杂

    那么这个时候用工厂方法模式就能解决这个难题了

    工厂方法模式是为每一个要创建的对象所在的类都相应地创建一个工厂

    代码如下

    @interface AnimalFactory:NSObject
    
    -(Animal*)createAnimal;
    
    @end;
    

    Dog工厂类

    @interface DogFactory:AnimalFactory;
    
    @implementation DogFactory
    
    -(Animal *)createAnimal{
    
        retrurn [[Dog alloc]init];
    
    }
    
    @end
    

    Cat工厂类

    @interface CatFactory:AnimalFactory;
    
    @implementation Cat Factory
    
    -(Animal *)createAnimal
    
        retrurn [[Cat alloc]init];
    
    }
    
    @end
    

    Main.m

    AnimalFactory *dogFactory=[[DogFactory alloc]init];
    
    Animal *animal1=[dogFactory createAnimal];
    
    [animal1 laugh];
    
    Animal *animal2=[dogFactory createAnimal];
    
    [animal2 laugh];
    
    …….
    
    Animal *animal100=[dogFactory createAnimal];
    
    [animal100 laugh];
    

    这样话如果要把100个Dog改为Cat的话,只需要吧DogFactory改为CatFactory就可以了

    但是工厂方法也有它的限制:

    • 1.要创建的类必须拥有同一个父类
    • 2.要创建的类在100个不同的地方所调用的方法必须一样

    优缺点

    优点:简单工厂模式的优点是客户端可以直接消费产品,而不必关心具体产品的实现,消除了客户端直接创建产品对象的责任,实现了对责任的分割。
    缺点:是工厂类几种了所有产品的创建逻辑,一旦不能正常工作,整个系统都会受到影响,而且当产品类多结构复杂的时候,把所有创建工作放进一个工厂中来,回事后期程序的扩展较为困难。

    通过优缺点的分析,我们可以再如下场景中使用简单工厂模式:
    (1)工厂类负责创建的对象较少时;
    (2)客户端只知道传入工厂类的参数,对于如何创建对象的逻辑不必关心时。

    3.代理模式(Proxy Pattern)

    定义:Provide a surrogate or placeholder for another object to control access to it.(为其他对象提供一种代理以控制对这个对象的访问。)

    场景:当一个类的某些功能需要由别的类来实现,但是又不确定具体会是哪个类实现。

    优势:解耦合

    敏捷原则:开放-封闭原则

    实例:tableview的 数据源delegate,通过和protocol的配合,完成委托诉求。

    • 列表row个数delegate
    • 自定义的delegate

    总之:当这个委托人需要办这些事时,代理人自己就站出来帮忙办了。这就是ios中的Delegate模式。

    4.观察者模式(Observer Pattern)

    定义:Define a one-to-many dependency between objects so that when one object changes state,all its dependents are notified and updated automatically.(定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。)

    • Subject被观察者

      定义被观察者必须实现的职责,它必须能够动态地增加、取消观察者。它一般是抽象类或者是实现类,仅仅完成作为被观察者必须实现的职责:管理观察者并通知观察者。

    • Observer观察者

      观察者接收到消息后,即进行update(更新方法)操作,对接收到的信息进行处理。

    • ConcreteSubject具体的被观察者

      定义被观察者自己的业务逻辑,同时定义对哪些事件进行通知。

    • ConcreteObserver具体的观察者

      每个观察在接收到消息后的处理反应是不同,各个观察者有自己的处理逻辑。

    使用场景:

    • 关联行为场景。需要注意的是,关联行为是可拆分的,而不是“组合”关系。
    • 事件多级触发场景。
    • 跨系统的消息交换场景,如消息队列的处理机制。

    注意:
    1、广播链的问题:在一个观察者模式中最多出现一个对象既是观察者也是被观察者,也就是说消息最多转发一次(传递两次)
    2、异步处理问题:
    观察者比较多,而且处理时间比较长,采用异步处理来考虑线程安全和队列的问题。

    实例:

    • Notification通知中心,注册通知中心,任何位置可以发送消息,注册观察者的对象可以接收。
    • kvo,键值对改变通知的观察者

    5.中介者模式

    定义:Define an object that encapsulates how a set of objects interact.Mediator promotes loose coupling by keeping objects from referring to each other explicitly,and it lets you vary their interaction independently.(用一个中介对象封装一系列的对象交互,中介者使各对象不需要显示地相互作用,从而使其耦合松散,而且可以独立地改变它们之间的交互。)

    • Mediator 抽象中介者角色:
      抽象中介者角色定义统一的接口,用于各同事角色之间的通信。
    • Concrete Mediator 具体中介者角色:
      具体中介者角色通过协调各同事角色实现协作行为,因此它必须依赖于各个同事角色。
    • Colleague 同事角色:
      每一个同事角色都知道中介者角色,而且与其他的同事角色通信的时候,一定要通过中介者角色协作。每个同事类的行为分为两种:一种是同事本身的行为,比如改变对象本身的状态,处理自己的行为等,这种行为叫做自发行为(Self-Method),与其他的同事类或中介者没有任何的依赖;第二种是必须依赖中介者才能完成的行为,叫做依赖方法(Dep-Method)。

    通用抽象中介者代码:

    public abstract class Mediator {
     //定义同事类
     protected ConcreteColleague1 c1;
     protected ConcreteColleague2 c2;
     //通过getter/setter方法把同事类注入进来
     public ConcreteColleague1 getC1() {
             return c1;
     }
     public void setC1(ConcreteColleague1 c1) {
             this.c1 = c1;
     }
     public ConcreteColleague2 getC2() {
             return c2;
    }
     public void setC2(ConcreteColleague2 c2) {
             this.c2 = c2;
     }
     //中介者模式的业务逻辑
     public abstract void doSomething1();
     public abstract void doSomething2();
    }
    

    ps:使用同事类注入而不使用抽象注入的原因是因为抽象类中不具有每个同事类必须要完成的方法。即每个同事类中的方法各不相同。

    问:为什么同事类要使用构造函数注入中介者,而中介者使用getter/setter方式注入同事类呢?

    这是因为同事类必须有中介者,而中介者却可以只有部分同事类。

    使用场景:
    中介者模式适用于多个对象之间紧密耦合的情况,紧密耦合的标准是:在类图中出现了蜘蛛网状结构,即每个类都与其他的类有直接的联系。

    实例:

    • 中间管理器 根据URLPath路由跳转
    • 随着模块化开发的兴起,各个模块间的调度跳转,需要中介者模式管理

    6.策略模式

    场景: 定义算法族,封装起来,使他们之间可以相互替换。

    优势:使算法的变化独立于使用算法的用户

    敏捷原则:接口隔离原则;多用组合,少用继承;针对接口编程,而非实现。

    实例:排序算法,NSArray的sortedArrayUsingSelector;经典的鸭子会叫,会飞案例。

    注意事项:

    1,剥离类中易于变化的行为,通过组合的方式嵌入抽象基类

    2,变化的行为抽象基类为,所有可变变化的父类

    3,用户类的最终实例,通过注入行为实例的方式,设定易变行为

    防止了继承行为方式,导致无关行为污染子类。完成了策略封装和可替换性。

    7.MVC模式

    MVC根据角色划分类,涉及到三个角色:

    Model: 模型保存应用程序的数据。

    View: 视图是模型的可视化表示以及用户交互的控件。

    Controller: 控制器是一个协调所有工作的中介者。它访问模型中的数据并在视图中展示它们,同时它们还监听事件和操作数据。

    一个MVC模式的好的实现也就意味着每一个对象都会被划分到上面所说的组中。

    我们可以很好的用下图来描述通过控制器实现的视图到模型的交互过程:

    image

    模型会把任何数据的变更通知控制器,然后控制器更新视图数据。视图对象通知控制器用户的操作,控制器要么根据需要来更新模型,要么检索任何被请求的数据。

    你可能在想为什么不能仅仅使用控制器,在一个类中实现视图和模型,这样貌似更加容易?

    所有的这些都归结于代码关注点分离以及复用。在理想的状态下,视图应该和模型完全的分离。如果视图不依赖某个实际的模型,那么视图就可以被复用来展示不同模型的数据。

    举个例子来说,如果将来你打算加入电影或者书籍到你的资料库中,你仍然可以使用同样的AlbumView去显示电影和书籍数据。更进一步来说,如果你想创建一个新的与专辑有关联的工程,你可以很简单的复用Album类,因为它不依赖任何视图。这就是MVC的强大之处。

    8.MVP模式

    MVP 模式将 Controller 改名为 Presenter,同时改变了通信方向。

    image

    1. 各部分之间的通信,都是双向的。

    2. View 与 Model 不发生联系,都通过 Presenter 传递。

    3. View 非常薄,不部署任何业务逻辑,称为"被动视图"(Passive View),即没有任何主动性,而 Presenter非常厚,所有逻辑都部署在那里。

    9.MVVM模式

    MVVM 模式将 Presenter 改名为 ViewModel,基本上与 MVP 模式完全一致。

    image

    唯一的区别是,它采用双向绑定(data-binding):View的变动,自动反映在 ViewModel,反之亦然。AngularEmber 都采用这种模式。

    相关文章

      网友评论

        本文标题:移动端常用设计模式浅析

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