基本概念
策略模式定义了算法族,分别封装起来, 让他们可以相互替换,此模式让算法的变化独立于使用算法的客户。
策略模式的重心不是如何来实现算法,而是如何组织、调用这些算法,从而让程序结构更灵活、具有更好的维护性和扩展性。
策略模式的本质:分离算法,选择实现。
策略模式优点:
- 算法可以自由切换(高层屏蔽算法,角色自由切换)
- 避免使用多重条件判断(如果算法过多就会出现很多种相同的判断,很难维护)
- 扩展性好(可自由添加取消算法 而不影响整个功能)
策略模式缺点:
- 策略类数量增多(每一个策略类复用性很小,如果需要增加算法,就只能新增类)
- 所有的策略类都需要对外暴露(使用的人必须了解使用策略,这个就需要其它模式来补充,比如工厂模式、代理模式)
UML类图
策略模式代码示例
在移动项目开发中,不可避免需要展示图片, 这就需要从server端获取图片路径。 通常来说不同图片类型在server端的存储路径会有所区别,并且返回的可能不一定是图片的完整路径。 下面给出用策略模式解决这种情况的代码示例。
创建策略接口:
1 2 3 4 5 6 7 8 9 10 11 12
| //server address let ResourceHost = "https://www.devzhang.cn"
protocol IResourcePathStrategy{ /// 路径拼接方法 /// /// - Parameter generateID: 资源id() /// - Returns: 资源全路径 func resourcePath(generateID:String)->String }
|
创建具体策略:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| /// 礼物资源图片路径拼接策略 class GiftResourcePathStrategy :IResourcePathStrategy{ let giftJointPath = "/img/gift/" func resourcePath(generateID:String) -> String { let giftPath = ResourceHost.appending(giftJointPath).appending(generateID).appending(".png") return giftPath; } }
/// 动画资源路径拼接策略 class AnimationResourcePathStrategy: IResourcePathStrategy { let animationJointPath = "/img/animation/" func resourcePath(generateID:String) -> String { let animationPath = ResourceHost.appending(animationJointPath).appending(generateID).appending(".zip") return animationPath; } }
/// 用户头像图片路径拼接策略 class AvatarResourcePathStrategy: IResourcePathStrategy { let avatarJointPath = "/img/avatar/" func resourcePath(generateID:String) -> String { let giftPath = ResourceHost.appending(avatarJointPath).appending(generateID).appending(".png") return giftPath; } }
|
创建策略上下文:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| class ResourcePathContext { //持有策略 private var strategy:IResourcePathStrategy /// 资源id private var generateID:String ///初始化策略上下文 init(stategy:IResourcePathStrategy, generateID:String) { self.strategy = stategy self.generateID = generateID } /// 调用具体策略实现 func generateResourcePath() -> String { return self.strategy.resourcePath(generateID: self.generateID); } }
|
客户端调用代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| //策略模式 //gift let giftStrategy = GiftResourcePathStrategy() let giftContext = ResourcePathContext(stategy: giftStrategy, generateID: "111") let giftResourcePath = giftContext.generateResourcePath() print("礼物id为111d的图片地址是" + giftResourcePath)
//animation let animationStrategy = AnimationResourcePathStrategy() let animationContext = ResourcePathContext(stategy: animationStrategy, generateID: "222") let animationResourcePath = animationContext.generateResourcePath() print("动画id为222的资源地址是" + animationResourcePath)
//avatar let avatarStrategy = AvatarResourcePathStrategy() let avatarContext = ResourcePathContext(stategy: avatarStrategy, generateID: "333") let avatarResourcePath = avatarContext.generateResourcePath() print("用户id为333的用户头像地址是" + avatarResourcePath)
|
策略枚举代码示例
策略枚举即在一个类中同时实现以上三种策略。
创建策略枚举类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| enum ResourcePath{ case giftResourcePath(giftID: String) case animationResourcePath(animation:String) case avatarResourcePath(avatar:String) private static var giftJointPath = "/img/gift/" private static var animationJointPath = "/img/animation/" private static var avatarJointPath = "/img/avatar/" var generateResourcePath:String { switch self { case .giftResourcePath(let giftID): return ResourceHost.appending(ResourcePath.giftJointPath).appending(giftID).appending(".png") case .animationResourcePath(let animationID): return ResourceHost.appending(ResourcePath.animationJointPath).appending(animationID).appending(".zip") case .avatarResourcePath(let userID): return ResourceHost.appending(ResourcePath.avatarJointPath).appending(userID).appending(".png") } } }
|
客户端调用:
1 2 3 4 5
| //策略枚举 print(ResourcePath.giftResourcePath(giftID: "111").generateResourcePath) print(ResourcePath.animationResourcePath(animation: "222").generateResourcePath) print(ResourcePath.avatarResourcePath(avatar: "333").generateResourcePath)
|