装饰者模式
Q:何为装饰模式?
()地给一个对象添加一些额外的(),并且()时,并不影响原对象。扩展功能来说,装饰器模式相比生成子类更为灵活。
Q:使用场景?
1.想要在不影响其他对象的情况下,以__、__的方式给单个对象添加职责。 2.想要()一个类的行为,却做不到。类定义可能被隐藏,无法进行子类化;或者,对类的每个行为的扩展,为支持每种功能组合,将产生大量的子类。 3.对类的()的扩展是可选的。
Q:主要角色?
4个核心角色 角色一:()组件 角色二:()组件 角色三:()者 角色四:()者
Q:CocoaTouch中的装饰模式实现方式?
1、装饰模式-定义
动态地给一个对象添加一些额外的职责,并且去除时,并不影响原对象。扩展功能来说,装饰器模式相比生成子类更为灵活。
2、装饰模式-场景
1.想要在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。 2.想要扩展一个类的行为,却做不到。类定义可能被隐藏,无法进行子类化;或者,对类的每个行为的扩展,为支持每种功能组合,将产生大量的子类。 3.对类的职责的扩展是可选的。
3与策略模式的差异
“外表变更”(装饰) | “内部变更”(策略) |
---|---|
从外部变更 | 从内部变更 |
每个节点不知道变更 | 每个节点知道一组预定义的变更方式 |
4、装饰模式-角色划分
4个核心角色 角色一:抽象组件 角色二:具体组件 角色三:抽象装饰者 角色四:具体装饰者
5、装饰模式-案例分析 swift实现
Decorator 案例:手机壳---iPhoneX->9688 角色一:抽象组件->MobilePhone(手机) 角色二:具体组件->iPhoneX 角色三:抽象装饰者->MobilePhoneShell 角色四:具体装饰者(具体扩展功能)-> 质量好的手机壳:耐磨、防水、防尘…(300) 耐磨:wearproof() 防水:waterproof() 防尘:dustproof() expensive() GoodShell
质量差的手机壳:耐磨(50) 便宜:cheap() PoorShell
//抽象组件->手机
protocol MobilePhone {
func shell()
}
//具体组件->iPhoneX
class IPhoneX: MobilePhone {
func shell() {
print("iPhoneX")
}
}
//具体组件->6S
class IPhone6S: MobilePhone {
func shell() {
print("iPhone6S")
}
}
//抽象装饰者 跟代理一样
//特点一:继承(实现)抽象组件
//特点二:持有抽象组件引用
class MobilePhoneShell: MobilePhone {
private var mobile:MobilePhone
init(mobile:MobilePhone) {
self.mobile = mobile
}
func shell() {
self.mobile.shell()
}
}
//具体装饰者->好的手机壳
class GoodShell: MobilePhoneShell {
override init(mobile: MobilePhone) {
super.init(mobile: mobile)
}
func wearproof(){
print("贵--耐磨功能")
}
func waterproof(){
print("贵--防水功能")
}
func dustproof(){
print("贵--防尘功能");
}
}
//具体装饰者->好的手机壳
class PoorShell: MobilePhoneShell {
override init(mobile: MobilePhone) {
super.init(mobile: mobile)
}
func wearproof(){
print("便宜--耐磨功能")
}
func cheap(){
print("便宜")
}
}
6.Cocoa Touch框架中使用装饰模式
6.1子类实现
[@protocol](https://my.oschina.net/u/819710) ImageComponent <NSObject>
// We will intercept these
// UIImage methods and add
// additional behavior
//截获UIImage的方法,插入附加行为
@optional
- (void) drawAsPatternInRect:(CGRect)rect;
- (void) drawAtPoint:(CGPoint)point;
- (void) drawAtPoint:(CGPoint)point blendMode:(CGBlendMode)blendMode alpha:(CGFloat)alpha;
- (void) drawInRect:(CGRect)rect;
- (void) drawInRect:(CGRect)rect blendMode:(CGBlendMode)blendMode alpha:(CGFloat)alpha;
[@end](https://my.oschina.net/u/567204)
#import "ImageComponent.h"
[@interface](https://my.oschina.net/u/996807) UIImage (ImageComponent) <ImageComponent>
[@end](https://my.oschina.net/u/567204)
#import "UIImage+ImageComponent.h"
//@implementation UIImage (ImageComponent)
//
//@end
#import "ImageComponent.h"
#import "UIImage+ImageComponent.h"
//核心装饰器类
@interface ImageFilter : NSObject <ImageComponent>
{
@private
id <ImageComponent> component_;//这个引用会被其他具体装饰器装饰
}
@property (nonatomic, retain) id <ImageComponent> component;
- (void) apply;
- (id) initWithImageComponent:(id <ImageComponent>) component;
- (id) forwardingTargetForSelector:(SEL)aSelector;//重载
/*
// overridden methods in UIImage APIs
- (void) drawAsPatternInRect:(CGRect)rect;
- (void) drawAtPoint:(CGPoint)point;
- (void) drawAtPoint:(CGPoint)point blendMode:(CGBlendMode)blendMode alpha:(CGFloat)alpha;
- (void) drawInRect:(CGRect)rect;
- (void) drawInRect:(CGRect)rect blendMode:(CGBlendMode)blendMode alpha:(CGFloat)alpha;
*/
@end
#import "ImageFilter.h"
@implementation ImageFilter
@synthesize component=component_;
- (id) initWithImageComponent:(id <ImageComponent>) component
{
if (self = [super init])
{
// save an ImageComponent
[self setComponent:component];
}
return self;
}
- (void) apply
{
// should be overridden by subclasses
// to apply real filters
//应该由子类重载,应用真正的滤镜
}
- (id) forwardingTargetForSelector:(SEL)aSelector
{
NSString *selectorName = NSStringFromSelector(aSelector);
if ([selectorName hasPrefix:@"draw"])
{
[self apply];
}
return component_;
}
/*
- (void) drawAsPatternInRect:(CGRect)rect
{
[self apply];
[component_ drawAsPatternInRect:rect];
}
- (void) drawAtPoint:(CGPoint)point
{
[self apply];
[component_ drawAtPoint:point];
}
- (void) drawAtPoint:(CGPoint)point blendMode:(CGBlendMode)blendMode alpha:(CGFloat)alpha
{
[self apply];
[component_ drawAtPoint:point
blendMode:blendMode
alpha:alpha];
}
- (void) drawInRect:(CGRect)rect
{
[self apply];
[component_ drawInRect:rect];
}
- (void) drawInRect:(CGRect)rect blendMode:(CGBlendMode)blendMode alpha:(CGFloat)alpha
{
[self apply];
[component_ drawInRect:rect
blendMode:blendMode
alpha:alpha];
}
*/
@end
装饰类:旋转+阴影
#import "ImageFilter.h"
@interface ImageTransformFilter : ImageFilter
{
@private
CGAffineTransform transform_;
CGSize size_;
}
@property (nonatomic, assign) CGAffineTransform transform;
@property (nonatomic, assign) CGSize size;
- (id) initWithImageComponent:(id <ImageComponent>)component
transform:(CGAffineTransform)transform
size:(CGSize )size;
- (void) apply;
@end
#import "ImageTransformFilter.h"
@implementation ImageTransformFilter
@synthesize transform = transform_;
@synthesize size = size_;
- (id) initWithImageComponent:(id <ImageComponent>)component
transform:(CGAffineTransform)transform
size:(CGSize )size
{
if (self = [super initWithImageComponent:component])
{
[self setTransform:transform];
size_ = size;
}
return self;
}
- (void) apply
{
// CGSize size = size_;
// if (NULL != UIGraphicsBeginImageContextWithOptions)
// UIGraphicsBeginImageContextWithOptions(size, NO, 0);
// else
// UIGraphicsBeginImageContext(size);
//
CGContextRef context = UIGraphicsGetCurrentContext();
// setup transformation
CGContextConcatCTM(context, transform_);
}
@end
#import "ImageFilter.h"
@interface ImageShadowFilter : ImageFilter
- (void) apply;
@end
@implementation ImageShadowFilter
- (void) apply
{
CGContextRef context = UIGraphicsGetCurrentContext();
// set up shadow
CGSize offset = CGSizeMake (-25, 15);
CGContextSetShadow(context, offset, 20.0);
}
@end
6.2分类实现
@interface UIImage (BaseFilter)
- (CGContextRef) beginContext;
- (UIImage *) getImageFromCurrentImageContext;
- (void) endContext;
@end
#import "UIImage+BaseFilter.h"
@implementation UIImage (BaseFilter)
- (CGContextRef) beginContext
{
// Create a graphics context with the target size
// On iOS 4 and later, use UIGraphicsBeginImageContextWithOptions
// to take the scale into consideration
// On iOS prior to 4, fall back to use UIGraphicsBeginImageContext
CGSize size = [self size];
if (NULL != UIGraphicsBeginImageContextWithOptions)
UIGraphicsBeginImageContextWithOptions(size, NO, 0);
else
UIGraphicsBeginImageContext(size);
CGContextRef context = UIGraphicsGetCurrentContext();
return context;
}
- (UIImage *) getImageFromCurrentImageContext
{
[self drawAtPoint:CGPointZero];
// Retrieve the UIImage from the current context
UIImage *imageOut = UIGraphicsGetImageFromCurrentImageContext();
return imageOut;
}
- (void) endContext
{
UIGraphicsEndImageContext();
}
@end
@interface UIImage (Transform)
- (UIImage *) imageWithTransform:(CGAffineTransform)transform;
@end
@implementation UIImage (Transform)
- (UIImage *) imageWithTransform:(CGAffineTransform)transform
{
CGContextRef context = [self beginContext];
// setup transformation
CGContextConcatCTM(context, transform);
// Draw the original image to the context
UIImage *imageOut = [self getImageFromCurrentImageContext];
[self endContext];
return imageOut;
}
@end
@interface UIImage (Shadow)
- (UIImage *) imageWithDropShadow;
@end
#import "UIImage+BaseFilter.h"
@implementation UIImage (Shadow)
- (UIImage *) imageWithDropShadow
{
CGContextRef context = [self beginContext];
// set up shadow
CGSize offset = CGSizeMake (-25, 15);
CGContextSetShadow(context, offset, 20.0);
// Draw the original image to the context
UIImage * imageOut = [self getImageFromCurrentImageContext];
[self endContext];
return imageOut;
}
@end
#import "ViewController.h"
#import "ImageTransformFilter.h"
#import "ImageShadowFilter.h"
#import "DecoratorView.h"
#import "UIImage+Transform.h"
#import "UIImage+Shadow.h"
@interface ViewController ()
@property (strong, nonatomic) IBOutlet UIImageView *OriginalPic;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
CGAffineTransform rotateTransform = CGAffineTransformMakeRotation(-M_PI / 4);
/*关于M_PI
#define M_PI 3.14159265358979323846264338327950288
进行旋转
一般我们理解的旋转为:0-360(度)
CGAffineTransformMakeRotation方法,使用的是M_PI的方式。
转化公式:0-360=0-2M_PI
M_PI = 180
CGAffineTransformMakeRotation(M_PI * -0.5);
也就是旋转-90度
*/
CGAffineTransform translateTransform = CGAffineTransformMakeTranslation
(-self.OriginalPic.image.size.width/6 ,self.OriginalPic.image.size.height/2);
CGAffineTransform finalTransform = CGAffineTransformConcat(rotateTransform, translateTransform);
// a true subclass approach
id <ImageComponent> transformedImage = [[ImageTransformFilter alloc] initWithImageComponent:self.OriginalPic.image transform:finalTransform size:(self.OriginalPic.frame.size)];
id <ImageComponent> finalImage = [[ImageShadowFilter alloc] initWithImageComponent:transformedImage];
[self CategoriesMethod:finalTransform];
}
-(void)CategoriesMethod:(CGAffineTransform)finalTransform{
// a category approach
// add transformation
UIImage *transformedImage = [self.OriginalPic.image imageWithTransform:finalTransform];
// add shadow
// id <ImageComponent> finalImage = [transformedImage imageWithDropShadow];
UIImage * finalImage = [transformedImage imageWithDropShadow];
// category approach in one line
// id <ImageComponent> finalImage = [[image imageWithTransform:finalTransform] imageWithDropShadow];
DecoratorView *decoratorView = [[DecoratorView alloc] initWithFrame:CGRectMake(67, 359, 255, 264)];//y 20 y 359
[decoratorView setImage:finalImage];
// [self.FilterPic setImage:finalImage];
[self.view addSubview:decoratorView];
}
@end
@interface DecoratorView : UIView
{
@private
UIImage *image_;
}
@property (nonatomic, retain) UIImage *image;
@end
#import "DecoratorView.h"
@implementation DecoratorView
@synthesize image=image_;
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
// Initialization code.
[self setBackgroundColor:[UIColor clearColor]];
}
return self;
}
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code.
[image_ drawInRect:rect];
}
//- (void)dealloc {
// [super dealloc];
//}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
// Drawing code
}
*/
@end