文档章节

装饰者模式

阿元
 阿元
发布于 09/19 22:36
字数 1722
阅读 5
收藏 0

装饰者模式

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

© 著作权归作者所有

共有 人打赏支持
上一篇: 11.属性
下一篇: 代理模式
阿元
粉丝 5
博文 163
码字总数 108443
作品 0
浦东
程序员
私信 提问
设计模式——装饰者模式:婚纱照收费的简单实现

装饰者模式 在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。 装饰者模式特点 装饰者和被装饰对象有相同的超类型...

OSC一霸
2016/10/20
3K
12
Decorator 装饰者模式

动机 我们可以通过继承来静态地(在编译期间)扩展对象的功能,不过有时我们也需要在使用对象的时候动态地(在运行时)扩展它 。 我来看一个经典的例子,图形窗口。比如说我们要扩展这个图形...

holysu
2017/11/26
0
0
Head First Design Pattern 读书笔记(3)装饰者模式

Head First Design Pattern 读书笔记(3) Decorator Pattern 装饰者模式 Decorator Pattern 类图 ![装饰者模式类图][2] 定义 装饰者模式:通过让组件类与装饰者类实现相同的接口,装饰类可以...

Tek_Eternal
2015/01/03
0
0
Pattern-No.05 设计模式之装饰者模式

1、装饰者模式定义:动态的将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。装饰者与被装饰者拥有共同的超类,继承的目的是继承类型,而不是行为。 2、要点 具体被...

蓝汀华韶
2015/04/03
0
0
设计模式之装饰者模式(Decorator Pattern)

模式分析: 动态地给一个对象添加一些额外的职责。就增加功能来说, Decorator模式相比生成子类更为灵活。该模式以对客 户端透明的方式扩展对象的功能。 使用情景: 在不影响其他对象的情况下...

bug_404
01/18
0
0

没有更多内容

加载失败,请刷新页面

加载更多

js垃圾回收机制和引起内存泄漏的操作

JS的垃圾回收机制了解吗? Js具有自动垃圾回收机制。垃圾收集器会按照固定的时间间隔周期性的执行。 JS中最常见的垃圾回收方式是标记清除。 工作原理:是当变量进入环境时,将这个变量标记为“...

Jack088
昨天
10
0
大数据教程(10.1)倒排索引建立

前面博主介绍了sql中join功能的大数据实现,本节将继续为小伙伴们分享倒排索引的建立。 一、需求 在很多项目中,我们需要对我们的文档建立索引(如:论坛帖子);我们需要记录某个词在各个文...

em_aaron
昨天
13
0
"errcode": 41001, "errmsg": "access_token missing hint: [w.ILza05728877!]"

Postman获取微信小程序码的时候报错, errcode: 41001, errmsg: access_token missing hint 查看小程序开发api指南,原来access_token是直接当作parameter的(写在url之后),scene参数一定要...

两广总督bogang
昨天
18
0
MYSQL索引

索引的作用 索引类似书籍目录,查找数据,先查找目录,定位页码 性能影响 索引能大大减少查询数据时需要扫描的数据量,提高查询速度, 避免排序和使用临时表 将随机I/O变顺序I/O 降低写速度,占用磁...

关元
昨天
11
0
撬动世界的支点——《引爆点》读书笔记2900字优秀范文

撬动世界的支点——《引爆点》读书笔记2900字优秀范文: 作者:挽弓如月。因为加入火种协会的读书活动,最近我连续阅读了两本论述流行的大作,格拉德威尔的《引爆点》和乔纳伯杰的《疯传》。...

原创小博客
昨天
30
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部