设计模之项目实战

简介: 设计模之项目实战

这本书相信大家也多多少少看过好多次了.可我自己仅仅也只是看而已.

直到看到别人用设计模式写出优雅的代码,才发现!

这些设计模式,自己都懂....

可是从来就没有把它实际的用到代码中.项目中写的最顺手的还是MVC慢慢的项目变庞大了,或许公司就倒了....

OK,来扯一个实际场景,首先我一个展示一个视图,然后从服务器中请求数据,再把请求下来的数据,填充到视图中展示出来.就这么一个逻辑.
方案一: 经典MVC

1.Model

2.View

3.controller

方案二: MVVM

1.Model

2.View

3.viewModel

4.controller

方案三 工厂模式|组合模式,路由?

1.view {

Cells

view

}

2.controllers

3.EnterRoom

4.privateTools {

ActionTools

FormatTools

ViewTools

}

5.protocol

这一回重点讲述方案三.

View,cells,跟Controller,我就不多扯了大伙都明白.

EnterRoom 负责 跳转控制器举个例子

控制器A想push到控制器B
那么传统的是
UIViewControler *vc = [UIViewController new];
[self.navigationController pushViewController:vc animated:YES];
按照工厂模式,路由跳转
id vc = [MTCollegeEnterRoom viewController];
[self.navigationController pushViewController:vc animated:YES];
有没有觉得好奇?我为什么要单独写一个类来做生成控制器的事情?
好处有如下.
1.在其他控制器中,我跳转不必要导入其他的控制器头文件.
2.在跳转控制时,我不必在写生成控制器的代码.
3.减少类与类之间的耦合,如何非得关联,则加一个中间层. MTCollegeEnterRoom这个就是中间层,曾经读到一段话:没有什么事情是加一个中间层不能解决的,不过不行就再加一个.
设想一下: 工厂 - 全国代理商 -省级区域代理商 - 县级区域代理商 - 专卖店
这个不就是中间层吗?生活中例子随处可见不浪费时间了.

下面来介绍如何生成视图了对不对?

老套路老规矩 
MTHeaderView *view = [MTHeaderView headerView];
self.tableView.tableHeaderView = headerView;
按照工厂模式,路由跳转
UIView *headerView = [MTViewFactory collegeMusicHeaderView];
self.tableView.tableHeaderView = headerView;
你瞧是不是很熟悉?很控制器的套路几乎一样,又是套了一个中间层.
这是时候,你估计会想到,既然没有导入头文件,那么我要用点语法怎么办?
难不成继续强转?导入头文件?
NONONO!
如果你需要给属性赋值,可以在外界提供一个Dict或者模型.
利用KVC
[headerView setValue:model forKey:@"model"];
在headerView内部做赋值刷新.
我想你肯定又要问,如果有代理时间怎么办?或者block
按照工厂模式,路由跳转
UIView *headerView = [MTViewFactory collegeMusicHeaderViewDelegate:self];
self.tableView.tableHeaderView = headerView;
在方法内部
举个例子
+ (UIView *) collegeMusicHeaderViewDelegate:(id<MTCollegeMusicHeaderView>)delegate{
   MTCollegeMusicHeaderView *headerView = [MTCollegeMusicHeaderView mtNew];
  headerView.delegate = delegate;
   return headerView;
}
block也是同理,在我项目中可以说全局用的delegate,只需要代理方法按照规范去写,我想接盘侠会很舒服的.

下面protocol

个就没有什么好说的了,在.h全部用@class,不直接导类,把每个模块的代理写在单独的一个类里面,用的时候只需要引入protocol 就好了.

介绍这个类了FormatTools

按照单一职责的思想,我们把功能模块全部细致划分.

我还是举个代码例子

先看.h

//
//  MTSpectralDetailsFormatter.h
//  LoveGuQin
//
//  Created by fox on 2018/5/28.
//  Copyright © 2018年 Moemoe. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "CollegeProtocol.h"
@class MTSpectralDetailsModel;
@interface MTSpectralDetailsFormatter : NSObject <UITableViewDelegate,UITableViewDataSource>
@property(nonatomic,weak)id <MTSpectralDetailsLoopCellDelegate>delegate;
- (instancetype)initWithTableView:(UITableView *)tablewView;
@property(nonatomic,strong)MTSpectralDetailsModel *detailsModel;
@end

再看.m

//
//  MTSpectralDetailsFormatter.m
//  LoveGuQin
//
//  Created by fox on 2018/5/28.
//  Copyright © 2018年 Moemoe. All rights reserved.
//
#import "MTSpectralDetailsFormatter.h"
#import "MTViewFactory+College.h"
#import "MTSpectralDetailsCell.h"
#import "MTCollegeEnterRoom.h"
#import "MTSpectralDetailsLoopCell.h"
#import "MTSpectralDetailsModel.h"
@interface MTSpectralDetailsFormatter ()<MTJoinWeCellDelegate>
@property(nonatomic,strong)UITableView *tableView;
@end
@implementation MTSpectralDetailsFormatter
- (instancetype)initWithTableView:(UITableView *)tableView {
    if (self = [super init]) {
        self.tableView = tableView;
    [tableView registerClass:[MTSpectralDetailsCell class] forCellReuseIdentifier:NSStringFromClass([MTSpectralDetailsCell class])];
    [tableView registerClass:[MTSpectralDetailsLoopCell class] forCellReuseIdentifier:NSStringFromClass([MTSpectralDetailsLoopCell class])];
    }
    return self;
}
- (void)setDetailsModel:(MTSpectralDetailsModel *)detailsModel {
    _detailsModel = detailsModel;
    [_tableView reloadData];
}
- (nonnull UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath {
    if (indexPath.row == 0) {
        MTSpectralDetailsCell *cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass([MTSpectralDetailsCell class]) forIndexPath:indexPath];
        cell.titleString = self.detailsModel.data.content;
        return cell;
    }else {
        MTSpectralDetailsLoopCell *cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass([MTSpectralDetailsLoopCell class]) forIndexPath:indexPath];
        cell.dataArray = self.detailsModel.data.scans;
        cell.delegate = self.delegate;
        return cell;
    }
}
- (NSInteger)tableView:(nonnull UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return 2;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}
#pragma mark - ********* College Delegate *********
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    if (indexPath.row == 0) {
       CGFloat height = [self.detailsModel.data.content sizeForFont:[UIFont systemFontOfSize:15] size:CGSizeMake(kScreenWidth - 48, 0) mode:0].height;
        return height;
    }else {
        return 200;
    }
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
    return 0;
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
    return 0;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
    return nil;
}
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section {
    return nil;
}
@end

发现没有,这个好处不需要我多说了吧.这一项,我已经把tableView的一系列相关代码移到这里来了.

这个时候再去看对应的控制器代码就简洁了..

//
//  MTSpectralController.m
//  LoveGuQin
//
//  Created by fox on 2018/5/26.
//  Copyright © 2018年 Moemoe. All rights reserved.
//
#import "MTSpectralController.h"
#import "MTViewFactory+Music.h"
#import "MTSpectralFormatter.h"
#import "MTSpectralRequest.h"
#import "MTSpectralModel.h"
#import "MTCollegeEnterRoom.h"
@interface MTSpectralController ()<MTMainMusicNavSearchViewDelegate,YTKRequestDelegate>
@property(nonatomic,strong)UIView *searchView;
@property(nonatomic,strong)UITableView *tableView;
@property(nonatomic,strong)MTSpectralFormatter *formatter;
@property(nonatomic,strong)NSArray <MTSpectraldataModel *>*dataArray;
@end
@implementation MTSpectralController
- (void)moeupNavigation {
    [self hideNav:YES withAnimation:NO];
    [self mtNavTransparent];
}
- (void)moeupSubview {
    self.searchView = [MTViewFactory searchVeiw:self withPlaceholdString:@"搜索琴曲" WithStyle:MTNavSearchReturn];
    [self.view addSubview:self.searchView];
    [self.view addSubview:self.tableView];
}
- (void)moeupData {
  MTSpectralRequest *request = [[MTSpectralRequest alloc]init];
    request.delegate = self;
    [request start];
}
#pragma MARK -- YTKRequestDelegate
- (void)requestFinished:(__kindof YTKBaseRequest *)request {
    MTSpectralModel *model = [MTSpectralModel yy_modelWithDictionary:request.responseObject];
    if ([model.code integerValue] == 1) {
        self.dataArray = model.data;
        self.formatter.dataArray =  self.dataArray;
    }else {
        [MBProgressHUD MT_ShowError:model.message];
    }
}
- (void)requestFailed:(__kindof YTKBaseRequest *)request {
    NSString *error = request.error.localizedDescription;
    [MBProgressHUD MT_ShowError:error];
}
- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];
    self.searchView.frame = CGRectMake(24 *kScale, MT_ASPECT_STATUS_BAR_H + 15, kScreenWidth - 48 *kScale, 44);
    self.tableView.frame = CGRectMake(0, self.searchView.bottom + 20 , MT_SCREEN_WIDTH, MT_SCREEN_HEIGHT - self.searchView.bottom - 20);
}
#pragma MARK -- MTMainMusicNavSearchViewDelegate
- (void)musicNavSearchViewTextFieldDidBeginEditing:(UITextField *)textField searchView:(MTMainMusicNavSearchView *)searchView {
    [textField resignFirstResponder];
    [self.navigationController pushViewController:[MTCollegeEnterRoom searchMainController] animated:YES];
}
- (void)musicNavSearchViewSearchClickReturn {
    [self mtPopback];
}
- (UITableView *)tableView{
    if (!_tableView) {
        _tableView = [[UITableView alloc]initWithFrame:CGRectZero style:UITableViewStyleGrouped];
        _tableView.delegate = self.formatter;
        _tableView.dataSource = self.formatter;
        _tableView.showsVerticalScrollIndicator = NO;
        _tableView.showsHorizontalScrollIndicator = NO;
        _tableView.backgroundColor = [UIColor whiteColor];
        _tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
    }
    return _tableView;
}
- (MTSpectralFormatter *)formatter{
    if (!_formatter) {
        _formatter = [[MTSpectralFormatter alloc]initWithTableView:_tableView];
        _formatter.dataArray = self.dataArray;
    }
    return _formatter;
}
@end

最后一个ActionTools

这个相信就不需要我多讲了吧?

这个自行斟酌,有些可以你写个代理放到控制器.

如果是纯点击跳转,可以独立写个类ActionTools

最后一个提示,cell其实也是可以复用的.比如说cell是容器,但是可以把它里面的东西写成一个XIB或者代码自定义View,这样,你拿View去到处复用,不是很happy?
一个工程都按照如上套路写,工程再大又何妨?

iOS很简单,也很难.入门简单,当知道的越多的时候,越感到无知......

OK.写了一个半个早上.如果对你有用,点个👍,或者打赏可好?嘿嘿!😜


相关文章
|
存储 网络协议 Linux
C++项目实战-实际应用(一)
C++项目实战-实际应用(一)
97 0
|
3月前
|
编解码 网络协议 Oracle
java网络编程入门以及项目实战
这篇文章是Java网络编程的入门教程,涵盖了网络编程的基础知识、IP地址、端口、通讯协议(TCP和UDP)的概念与区别,并提供了基于TCP和UDP的网络编程实例,包括远程聊天和文件传输程序的代码实现。
java网络编程入门以及项目实战
|
存储 搜索推荐 Linux
5个值得学习的C++完整项目实战
5个值得学习的C++完整项目实战
|
移动开发 运维 前端开发
【深入浅出全栈开发】全栈是什么?- 课前必读 #154
【深入浅出全栈开发】全栈是什么?- 课前必读 #154
601 0
|
缓存 算法 Java
C++项目实战-实际应用(二)
C++项目实战-实际应用(二)
69 0
项目实战——产品设计
项目实战——产品设计
68 0
|
监控
项目实战-产品设计
项目实战-产品设计
|
前端开发
项目实战14—前端代码优化
项目实战14—前端代码优化
74 0
|
数据采集 开发者 SEO
介绍CabloyJS全栈框架的功能特点
CabloyJS是一款全栈框架,它自带工作流引擎,并提供了丰富的SEO工具和报告。作为一个低代码开发平台,CabloyJS的跨端跨平台理念可以帮助开发者实现一次开发,到处运行的目标。此外,CabloyJS还提供了网页信息分析、数据采集和代理IP等功能。
介绍CabloyJS全栈框架的功能特点