美文网首页
iOS设计模式之访问者模式

iOS设计模式之访问者模式

作者: 点滴86 | 来源:发表于2024-07-01 23:34 被阅读0次

访问者模式

电脑上有很多资源文件,它们的格式有三种:PDF、PPT、Word。现在要开发一个工具来处理这批资源文件。这个工具的其中一个功能是,把这些资源文件中的文本内容抽取出来放到txt文件中。

@protocol DMResourceFileDelegate <NSObject>

- (void)extractTxt;

@end

@interface DMPDFFile : NSObject <DMResourceFileDelegate>

@end

@implementation DMPDFFile

- (void)extractTxt
{
    NSLog(@"%@:%@", NSStringFromClass([self class]), NSStringFromSelector(_cmd));
}

@end

@interface DMPPTFile : NSObject <DMResourceFileDelegate>

@end

@implementation DMPPTFile

- (void)extractTxt
{
    NSLog(@"%@:%@", NSStringFromClass([self class]), NSStringFromSelector(_cmd));
}

@end

@interface DMWordFile : NSObject <DMResourceFileDelegate>

@end

@implementation DMWordFile

- (void)extractTxt
{
    NSLog(@"%@:%@", NSStringFromClass([self class]), NSStringFromSelector(_cmd));
}

@end

@interface DMToolApplication : NSObject

@end

@implementation DMToolApplication

- (void)test
{
    NSMutableArray<DMResourceFileDelegate> *tmpArray = [[NSMutableArray<DMResourceFileDelegate> alloc] init];
    DMPDFFile *pdfFile = [[DMPDFFile alloc] init];
    [tmpArray addObject:pdfFile];
    
    DMPPTFile *pptFile = [[DMPPTFile alloc] init];
    [tmpArray addObject:pptFile];
    
    DMWordFile *wordFile = [[DMWordFile alloc] init];
    [tmpArray addObject:wordFile];
    
    for (id<DMResourceFileDelegate> resourceFile in tmpArray) {
        [resourceFile extractTxt];
    }
}

@end

如果工具的功能不停地扩展,不仅要能抽取文本内容,还要支持压缩、提取元文件信息(文件名、大小、更新时间等等)构建索引等一系列的功能,继续按照上面代码的实现思路,就会存在几个问题:

  • 违背开闭原则,添加一个新的功能,所有类的代码都要修改
  • 虽然功能增多,每个类的代码都不断膨胀,可读性和可维护性都变差了
  • 把所有比较上层的业务逻辑都耦合到DMPDFFile、DMPPTFile、DMWordFile类中,导致这些类的职责不够单一,变成了大杂烩

针对上面的问题,常用的解决方法就是拆分解耦,把业务操作跟具体的数据结构解耦,设计成独立的类。重构之后的代码如下:

@interface DMPDFFile : NSObject

@end

@implementation DMPDFFile

@end

@interface DMPPTFile : NSObject

@end

@implementation DMPPTFile

@end

@interface DMWordFile : NSObject

@end

@implementation DMWordFile

@end

@interface DMExtractor : NSObject

- (void)extractPDF:(DMPDFFile *)pdfFile;

- (void)extractPPT:(DMPPTFile *)pptFile;

- (void)extractWord:(DMWordFile *)wordFile;

@end

@implementation DMExtractor

- (void)extractPDF:(DMPDFFile *)pdfFile
{
    
}

- (void)extractPPT:(DMPPTFile *)pptFile
{
    
}

- (void)extractWord:(DMWordFile *)wordFile
{
    
}

@end

@interface DMToolApplication : NSObject

@end

@implementation DMToolApplication

- (void)test
{
    DMExtractor *extractor = [[DMExtractor alloc] init];
    
    NSMutableArray *tmpArray = [[NSMutableArray alloc] init];
    DMPDFFile *pdfFile = [[DMPDFFile alloc] init];
    [tmpArray addObject:pdfFile];
    
    DMPPTFile *pptFile = [[DMPPTFile alloc] init];
    [tmpArray addObject:pptFile];
    
    DMWordFile *wordFile = [[DMWordFile alloc] init];
    [tmpArray addObject:wordFile];
    
    for (id resourceFile in tmpArray) {
        if ([resourceFile isKindOfClass:[DMPDFFile class]]) {
            DMPDFFile *pdfFile = (DMPDFFile *)resourceFile;
            [extractor extractPDF:pdfFile];
        } else if ([resourceFile isKindOfClass:[DMPPTFile class]]) {
            DMPPTFile *pptFile = (DMPPTFile *)resourceFile;
            [extractor extractPPT:pptFile];
        } else if ([resourceFile isKindOfClass:[DMWordFile class]]) {
            DMWordFile *wordFile = (DMWordFile *)resourceFile;
            [extractor extractWord:wordFile];
        }
    }
}

@end

遍历tmpArray获取resourceFile,需要手动转换类型,调用对应的方法,继续优化这部分

@class DMExtractor;

@protocol DMResourceFileDelegate <NSObject>

- (void)accept:(DMExtractor *)extractor;

@end

@interface DMPDFFile : NSObject <DMResourceFileDelegate>

@end

@implementation DMPDFFile

- (void)accept:(DMExtractor *)extractor
{
    [extractor extractPDF:self];
}

@end

@interface DMPPTFile : NSObject <DMResourceFileDelegate>

@end

@implementation DMPPTFile

- (void)accept:(DMExtractor *)extractor
{
    [extractor extractPPT:self];
}

@end

@interface DMWordFile : NSObject <DMResourceFileDelegate>

@end

@implementation DMWordFile

- (void)accept:(DMExtractor *)extractor
{
    [extractor extractWord:self];
}

@end

@interface DMExtractor : NSObject

- (void)extractPDF:(DMPDFFile *)pdfFile;

- (void)extractPPT:(DMPPTFile *)pptFile;

- (void)extractWord:(DMWordFile *)wordFile;

@end

@implementation DMExtractor

- (void)extractPDF:(DMPDFFile *)pdfFile
{
    
}

- (void)extractPPT:(DMPPTFile *)pptFile
{
    
}

- (void)extractWord:(DMWordFile *)wordFile
{
    
}

@end

@interface DMToolApplication : NSObject

@end

@implementation DMToolApplication

- (void)test
{
    DMExtractor *extractor = [[DMExtractor alloc] init];
    
    NSMutableArray<DMResourceFileDelegate> *tmpArray = [[NSMutableArray<DMResourceFileDelegate> alloc] init];
    DMPDFFile *pdfFile = [[DMPDFFile alloc] init];
    [tmpArray addObject:pdfFile];
    
    DMPPTFile *pptFile = [[DMPPTFile alloc] init];
    [tmpArray addObject:pptFile];
    
    DMWordFile *wordFile = [[DMWordFile alloc] init];
    [tmpArray addObject:wordFile];
    
    for (id<DMResourceFileDelegate> resourceFile in tmpArray) {
        [resourceFile accept: extractor];
    }
}

@end

现在,如果要继续添加新的功能,比如前面提到的压缩功能,根据不同的文件类型,使用不同的压缩算法来压缩资源文件。代码实现如下:

@class DMExtractor;
@class DMCompressor;

@protocol DMResourceFileDelegate <NSObject>

- (void)accept:(DMExtractor *)extractor;

- (void)acceptCompressor:(DMCompressor *)compressor;

@end

@interface DMPDFFile : NSObject <DMResourceFileDelegate>

@end

@implementation DMPDFFile

- (void)accept:(DMExtractor *)extractor
{
    [extractor extractPDF:self];
}

- (void)acceptCompressor:(DMCompressor *)compressor
{
    [compressor compressPDF:self];
}

@end

@interface DMPPTFile : NSObject <DMResourceFileDelegate>

@end

@implementation DMPPTFile

- (void)accept:(DMExtractor *)extractor
{
    [extractor extractPPT:self];
}

- (void)acceptCompressor:(DMCompressor *)compressor
{
    [compressor compressPPT:self];
}

@end

@interface DMWordFile : NSObject <DMResourceFileDelegate>

@end

@implementation DMWordFile

- (void)accept:(DMExtractor *)extractor
{
    [extractor extractWord:self];
}

- (void)acceptCompressor:(DMCompressor *)compressor
{
    [compressor compressWord:self];
}

@end

@interface DMExtractor : NSObject

- (void)extractPDF:(DMPDFFile *)pdfFile;

- (void)extractPPT:(DMPPTFile *)pptFile;

- (void)extractWord:(DMWordFile *)wordFile;

@end

@implementation DMExtractor

- (void)extractPDF:(DMPDFFile *)pdfFile
{
    
}

- (void)extractPPT:(DMPPTFile *)pptFile
{
    
}

- (void)extractWord:(DMWordFile *)wordFile
{
    
}

@end

@interface DMCompressor : NSObject

- (void)compressPDF:(DMPDFFile *)pdfFile;

- (void)compressPPT:(DMPPTFile *)pptFile;

- (void)compressWord:(DMWordFile *)wordFile;

@end

@implementation DMCompressor

- (void)compressPDF:(DMPDFFile *)pdfFile
{
    NSLog(@"%@:%@", NSStringFromClass([self class]), NSStringFromSelector(_cmd));
}

- (void)compressPPT:(DMPPTFile *)pptFile
{
    NSLog(@"%@:%@", NSStringFromClass([self class]), NSStringFromSelector(_cmd));
}

- (void)compressWord:(DMWordFile *)wordFile
{
    NSLog(@"%@:%@", NSStringFromClass([self class]), NSStringFromSelector(_cmd));
}

@end

@interface DMToolApplication : NSObject

@end

@implementation DMToolApplication

- (void)test
{
    NSLog(@"重构三");
    DMExtractor *extractor = [[DMExtractor alloc] init];
    DMCompressor *compressor = [[DMCompressor alloc] init];
    
    NSMutableArray<DMResourceFileDelegate> *tmpArray = [[NSMutableArray<DMResourceFileDelegate> alloc] init];
    DMPDFFile *pdfFile = [[DMPDFFile alloc] init];
    [tmpArray addObject:pdfFile];
    
    DMPPTFile *pptFile = [[DMPPTFile alloc] init];
    [tmpArray addObject:pptFile];
    
    DMWordFile *wordFile = [[DMWordFile alloc] init];
    [tmpArray addObject:wordFile];
    
    for (id<DMResourceFileDelegate> resourceFile in tmpArray) {
        [resourceFile accept:extractor];
    }
    
    for (id<DMResourceFileDelegate> resourceFile in tmpArray) {
        [resourceFile acceptCompressor:compressor];
    }
}
@end

上面的代码还存在一些问题,新添加一个新的业务,还是需要修改每个资源文件,违反了开闭原则。针对这个问题,做如下修改,
协议DMVisitor,三个方法- (void)visitPDF:(DMPDFFile *)pdfFile、- (void)visitPPT:(DMPPTFile *)pptFile、- (void)visitWord:(DMWordFile *)wordFile 分别处理三种不同类型的资源文件。具体做什么业务,由遵守这个协议的具体类来决定,比如DMExtractor负责抽取文本内容、DMCompressor负责压缩。当添加一个新的业务功能的时候,资源文件类不需要做任务修改,只需要新的业务功能遵守DMVisitor协议,实现对应的功能,就可以了。然后再修改下DMToolApplication的使用代码,如下:


@class DMPDFFile;
@class DMPPTFile;
@class DMWordFile;

@protocol DMVisitor <NSObject>

- (void)visitPDF:(DMPDFFile *)pdfFile;

- (void)visitPPT:(DMPPTFile *)pptFile;

- (void)visitWord:(DMWordFile *)wordFile;

@end

@interface DMExtractor : NSObject <DMVisitor>

@end

@implementation DMExtractor

- (void)visitPDF:(DMPDFFile *)pdfFile
{
    NSLog(@"%@:%@", NSStringFromClass([self class]), NSStringFromSelector(_cmd));
}

- (void)visitPPT:(DMPPTFile *)pptFile
{
    NSLog(@"%@:%@", NSStringFromClass([self class]), NSStringFromSelector(_cmd));
}

- (void)visitWord:(DMWordFile *)wordFile
{
    NSLog(@"%@:%@", NSStringFromClass([self class]), NSStringFromSelector(_cmd));
}

@end

@interface DMCompressor : NSObject <DMVisitor>

@end

@implementation DMCompressor

- (void)visitPDF:(DMPDFFile *)pdfFile
{
    NSLog(@"%@:%@", NSStringFromClass([self class]), NSStringFromSelector(_cmd));
}

- (void)visitPPT:(DMPPTFile *)pptFile
{
    NSLog(@"%@:%@", NSStringFromClass([self class]), NSStringFromSelector(_cmd));
}

- (void)visitWord:(DMWordFile *)wordFile
{
    NSLog(@"%@:%@", NSStringFromClass([self class]), NSStringFromSelector(_cmd));
}

@end

@protocol DMResourceFileDelegate <NSObject>

- (void)acceptVisitor:(id<DMVisitor>)visitor;

@end

@interface DMPDFFile : NSObject <DMResourceFileDelegate>

@end

@implementation DMPDFFile

- (void)acceptVisitor:(id<DMVisitor>)visitor
{
    [visitor visitPDF:self];
}

@end

@interface DMPPTFile : NSObject <DMResourceFileDelegate>

@end

@implementation DMPPTFile

- (void)acceptVisitor:(id<DMVisitor>)visitor
{
    [visitor visitPPT:self];
}

@end

@interface DMWordFile : NSObject <DMResourceFileDelegate>

@end

@implementation DMWordFile

- (void)acceptVisitor:(id<DMVisitor>)visitor
{
    [visitor visitWord:self];
}

@end

@interface DMToolApplication : NSObject

@end

@implementation DMToolApplication

- (void)test
{
    DMExtractor *extractor = [[DMExtractor alloc] init];
    DMCompressor *compressor = [[DMCompressor alloc] init];
    
    NSMutableArray<DMResourceFileDelegate> *tmpArray = [[NSMutableArray<DMResourceFileDelegate> alloc] init];
    DMPDFFile *pdfFile = [[DMPDFFile alloc] init];
    [tmpArray addObject:pdfFile];
    
    DMPPTFile *pptFile = [[DMPPTFile alloc] init];
    [tmpArray addObject:pptFile];
    
    DMWordFile *wordFile = [[DMWordFile alloc] init];
    [tmpArray addObject:wordFile];
    
    for (id<DMResourceFileDelegate> resourceFile in tmpArray) {
        [resourceFile acceptVisitor:extractor];
    }
    
    for (id<DMResourceFileDelegate> resourceFile in tmpArray) {
        [resourceFile acceptVisitor:compressor];
    }
}

@end

相关文章

网友评论

      本文标题:iOS设计模式之访问者模式

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