命令模式

第一點:將一個請求封裝成爲一個對象,從而讓用戶使用不一樣的請求將客戶端參數化。 第二點:對請求排隊或者紀錄請求日誌,以及支持撤銷操做。 讓咱們程序擴展性更加好了,耦合下降了。swift

命令模式-應用場景: 當須要將方法調用包裝成一個對象,以延時方法調用,或者讓其餘組件在對其內部實現細節不瞭解的狀況下進行調用的時候能夠使用命令模式api

場景一:應用程序支持撤銷和恢復 場景二:記錄請求日誌,當系統故障這些命令能夠從新被執行 場景三:想用對象參數化一個動做以執行操做,而且用不一樣命令對象來替換回調函數閉包

以命令模式進行分析:(思路) 管理器(請求者)--(調用)-->具體命令--(接口)-->接受者執行 命令模式至少有的4個角色:併發

  • 命令接口(抽象)(CommandProtocol):TMCommandProtocol
  • 具體命令(ConcrateCommand) 好比:1.向左-> TMLeftCommand 2.向右-> TMRightCommand 3.變型-> TMTransformCommand
  • 接受者(Reciever):TetrisMachine
  • 請求者 (命令管理器)(Invoker):TetrisMachineManger管理回調命令

案例需求:記錄全部操做,支持回退(撤銷)。app

import Foundation
//命令接口
protocol CommandProtocol {
	func excute()
}

//具體命令
class TMLeftCommand: CommandProtocol {
	
	private var tm : TetrisMachine
	
	init(_ tm:TetrisMachine) {
		self.tm = tm
	}
		
	func excute() {
		self.tm.Toleft()
	}
}

class TMRightCommand: CommandProtocol {
	private var tm : TetrisMachine
	
	init(_ tm:TetrisMachine) {
		self.tm = tm
	}
	
	func excute() {
		
		self.tm.ToRight()
	}
}

class TMTransformCommand: CommandProtocol {
	private var tm : TetrisMachine
	
	init(_ tm:TetrisMachine) {
		self.tm = tm
	}
	
	func excute() {
		self.tm.ToTransform()
	}
}

//接受者
class TetrisMachine : NSObject {
	func Toleft(){
		print("left")
	}
	
	func ToRight(){
		print("right")
	}
	
	func ToTransform(){
		print("transform")
	}
}

//請求者
class TetrisMachineManger{
	private var commands = Array<CommandProtocol>()
	private var tm : TetrisMachine
	private var left : TMLeftCommand
	private var right : TMRightCommand
	private var transform : TMTransformCommand
	
	init(tm:TetrisMachine, left:TMLeftCommand,right:TMRightCommand,transform:TMTransformCommand) {
		self.left = left
		self.right = right
		self.transform = transform
		self.tm = tm
	}
	
	func Toleft(){
		self.left.excute()
		self.commands.append(TMLeftCommand(self.tm))
		
	}
	
	func ToRight(){
		self.right.excute()
		self.commands.append(TMRightCommand(self.tm))
	}
	
	func ToTransform(){
		self.transform.excute()
		self.commands.append(TMTransformCommand(self.tm))
	}
	
	func undo(){
		if self.commands.count > 0{
			self.commands.removeLast().excute()
		}
	}
}

//最後調用
let tm = TetrisMachine()
		let left = TMLeftCommand(tm)
		let right = TMRightCommand(tm)
		let transform = TMTransformCommand(tm)
		let manager = TetrisMachineManger(tm: tm, left: left, right: right, transform: transform)
		
		manager.Toleft()
		manager.ToRight()
		manager.ToTransform()
		manager.undo()
		
		//打印
left
right
transform
transform

5.1 命令模式 泛型設計 動態調用

什麼是泛型:在定義的時候不須要指定類型,在使用的時候指定類型。(ObjectType)框架

1.聲明文件->指定泛型->T(任意標識) 2.實現文件->指定具體類型(id萬能指針->引用->指向任意對象)dom

[@interface](https://my.oschina.net/u/996807) NSMutableArray<ObjectType> : NSArray<ObjectType>
#import <Foundation/Foundation.h>
#import "TMCommandProtocol.h"
//T:表示任意類型標記(表示符)
[@interface](https://my.oschina.net/u/996807) GenericsCommand<T> : NSObject<TMCommandProtocol>
-(instancetype)init:(T)receiver block:(void(^)(T)) commandBlock;
+(id<TMCommandProtocol>)creatCommand:(T)receiver block:(void(^)(T)) commandBlock;
[@end](https://my.oschina.net/u/567204)

#import "GenericsCommand.h"
[@interface](https://my.oschina.net/u/996807) GenericsCommand<T>()
[@property](https://my.oschina.net/property) (nonatomic,strong)T receiver;
@property (nonatomic,strong)void(^commandblock)(T);
@end
@implementation GenericsCommand
//id 是指向泛型的引用
-(instancetype)init:(id)receiver block:(void(^)(id))commandBlock{
	self = [super init];
	if (self){
		self.receiver  = receiver ;
		self.commandblock = commandBlock;
	}
	return self;
}
-(void)execute{
	self.commandblock(self.receiver);
}
+(id<TMCommandProtocol>)creatCommand:(id)receiver block:(void(^)(id)) commandBlock{
	return [[GenericsCommand alloc]init:receiver block:commandBlock];
}
@end

#import <Foundation/Foundation.h>
#import "TetrisMachine.h"
@interface GenericsCommandManager : NSObject
-(instancetype)init:(TetrisMachine *)tm;
-(void)Toleft;
-(void)Toright;
-(void)Totransform;
-(void)undo;
-(void)Allundo;
@end

#import "GenericsCommandManager.h"
#import "GenericsCommand.h"
@interface GenericsCommandManager()
@property (nonatomic,strong)TetrisMachine *tm;
@property (nonatomic,strong)NSMutableArray *commands;
@end
@implementation GenericsCommandManager

-(instancetype)init:(TetrisMachine *)tm{
	self = [super init];
	if (self){
		self.tm = tm ;
		self.commands = [[NSMutableArray alloc]init];
	}
	return self;
}
-(void)Toleft{
	[self addCommand:@"Toleft"];
	[self.tm Toleft];//執行命令
}
-(void)Toright{
	[self addCommand:@"ToRight"];
	[self.tm ToRight];
}
-(void)Totransform{
	[self addCommand:@"ToTransform"];
	[self.tm ToTransform];
}

//管理器動態添加命令
-(void)addCommand:(NSString *)methodName{
	//根據方法名稱,動態加載執行對象的方法
	SEL method = NSSelectorFromString(methodName);
	//添加動態命令
	[self.commands addObject:[GenericsCommand creatCommand:self.tm block:^(TetrisMachine *tm) {
		//執行回調
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
		[tm performSelector:method];
#pragma clang diagnostic pop
	}]];
	
}
-(void)undo{
	NSLog(@"撤銷");
	if (self.commands.count > 0){
		//撤銷
		[[self.commands lastObject]execute];
		//移除
		[self.commands removeLastObject];
		
	}
}
-(void)Allundo{
	NSLog(@"刪除全部");
	//倒序co
	NSArray* reversedArray = [[self.commands reverseObjectEnumerator] allObjects];
	for (id<TMCommandProtocol> command in reversedArray){
		[command execute];
	}
	[self.commands removeAllObjects];
}
@end

5.2 命令模式 案例進階 block閉包 && 併發(優化框架)

#import <Foundation/Foundation.h>
#import "TetrisMachine.h"
@interface BlockCommandManager : NSObject
-(instancetype)init:(TetrisMachine *)tm;
-(void)Toleft;
-(void)Toright;
-(void)Totransform;
-(void)undo;
-(void)Allundo;
@end

#import "BlockCommandManager.h"
typedef void (^BlockCommand)(TetrisMachine *tm);
@interface BlockCommandManager()
@property (nonatomic,strong)TetrisMachine *tm;
@property (nonatomic,strong)NSMutableArray *commands;
@property (nonatomic,strong)dispatch_queue_t queue;
@end
@implementation BlockCommandManager

-(instancetype)init:(TetrisMachine *)tm{
	self = [super init];
	if (self){
		self.tm = tm ;
		self.commands = [[NSMutableArray alloc]init];
		self.queue = dispatch_queue_create("Command", NULL);
	}
	return self;
}
-(void)Toleft{
	[self addCommand:@"Toleft"];
	[self.tm Toleft];//執行命令
}
-(void)Toright{
	[self addCommand:@"ToRight"];
	[self.tm ToRight];
}
-(void)Totransform{
	[self addCommand:@"ToTransform"];
	[self.tm ToTransform];
}

//管理器動態添加命令
-(void)addCommand:(NSString *)methodName{
	//併發 
	dispatch_sync(self.queue, ^{
		//根據方法名稱,動態加載執行對象的方法
		SEL method = NSSelectorFromString(methodName);
		//添加動態命令  保存的是block
		[self.commands addObject:^(TetrisMachine *tm){
			#pragma clang diagnostic push
			#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
			[tm performSelector:method];
			#pragma clang diagnostic pop
		}];
	});
	
}
-(void)undo{
	NSLog(@"撤銷");
	if (self.commands.count > 0){
		//撤銷
		BlockCommand command =[self.commands lastObject];
		command(self.tm);
		//移除
		[self.commands removeLastObject];
	}
}
-(void)Allundo{
	NSLog(@"刪除全部");
	//倒序co
	NSArray* reversedArray = [[self.commands reverseObjectEnumerator] allObjects];
	for (BlockCommand command in reversedArray){
		command(self.tm);
	}
	[self.commands removeAllObjects];
}
@end

5.3swift優化泛型命令

import UIKit

class GenericsCommand<T>: CommandProtocol {
	private var tm : T
	private var  block : (T)->Void
	
	init(receiver : T ,block:@escaping (T) -> Void) {
		self.tm = receiver;
		self.block = block
	}
	func excute() {
		self.block(self.tm)
	}
	
	
	class func creatCommand(receiver:T,block:@escaping (T)->Void)->CommandProtocol {
		return GenericsCommand (receiver: receiver, block: block)
	}
}

import UIKit

class GenericsCommandInvoke: NSObject {
	private var reveiver : TetrisMachine
	private var commands = Array<CommandProtocol>()
	
	init(reveiver:TetrisMachine) {
		self.reveiver = reveiver
	}
	
	func toLeft(){
		self.addCommand(method: TetrisMachine.Toleft)
		self.reveiver.Toleft()
	}
	
	func toRight(){
		self.addCommand(method: TetrisMachine.ToRight)
		self.reveiver.ToRight()
	}
	
	func toTransform(){
		self.addCommand(method: TetrisMachine.ToTransform)
		self.reveiver.ToTransform()
	}
	
	//使用的指定
	private func addCommand(method:@escaping(TetrisMachine)->()->(Void)){
		self.commands.append(GenericsCommand<TetrisMachine>(receiver: self.reveiver, block: { (tm) in
			method(tm)()
		}))
	}
	//modify  多個直接撤銷
	func undo(){
		if self.commands.count>0{
			self.commands.removeLast().excute()
		}
	}
	
	func undoAll(){
		//		for commands in self.commands{
		//			commands.excute()
		//		}
		WrapperCommand(commands: self.commands).excute();
		self.commands.removeAll()
	}
}

5.4swift優化閉包命令

import UIKit

class BlockCommandInvoke: NSObject {
	private var queue = DispatchQueue(label: "Command")
	private var reveiver : TetrisMachine
	typealias BlockCommand = ((TetrisMachine) ->Void)
	private var commands = Array<BlockCommand>()
	
	init(reveiver:TetrisMachine) {
		self.reveiver = reveiver
	}
	
	func toLeft(){
		self.addCommand(method: TetrisMachine.Toleft)
		self.reveiver.Toleft()
	}
	
	func toRight(){
		self.addCommand(method: TetrisMachine.ToRight)
		self.reveiver.ToRight()
	}
	
	func toTransform(){
		self.addCommand(method: TetrisMachine.ToTransform)
		self.reveiver.ToTransform()
	}
	
	//
	private func addCommand(method:@escaping(TetrisMachine)->()->(Void)){
		self.queue.sync {
			self.commands.append({tm in
				method(tm)()
				})
		}
	}
	//modify  多個直接撤銷
	func undo(){
		if self.commands.count > 0{
			self.commands.removeLast()(self.reveiver)
		}
	}
	
	func undoAll(){
		for command in self.commands{
			command(self.reveiver)
		}
		self.commands.removeAll()
	}
}

參考文章:https://www.jianshu.com/p/c62e1bc04bf1 NSUndoManager:https://nshipster.cn/nsundomanager/函數

相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息