文档章节

装饰者模式

阿元
 阿元
发布于 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

© 著作权归作者所有

共有 人打赏支持
阿元
粉丝 5
博文 160
码字总数 105814
作品 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

没有更多内容

加载失败,请刷新页面

加载更多

[Hive]JsonSerde使用指南

注意: 重要的是每行必须是一个完整的JSON,一个JSON不能跨越多行,也就是说,serde不会对多行的Json有效。 因为这是由Hadoop处理文件的工作方式决定,文件必须是可拆分的,例如,Hadoop将在...

Mr_yul
14分钟前
0
0
54:mysql修改密码|连接mysql|mysql常用命令

1、mysql修改密码: root用户时mysql的超级管理员,默认mysql的密码是空的,直接可以连接上去的,不过这样不安全; 注释:为了方便的使用mysql,需要把mysql加入到环境变量里; #后续自己输入mys...

芬野de博客
21分钟前
0
0
鼠标单击复制粘贴标签中的内容

<span ref="spanContentOne" id="spanContentOne" style="font-size: 14px;">或许不是最亮眼,总比瞎买强一点</span><!--<input type="button" @click="copyClick('1')" value="复制" />-......

帝子兮
25分钟前
0
0
使用axel多线程疯狂下载

在Linux中比较常见见的下载工具是curl和wget,但是下载比较大的文件两者都不支持多线程, 断点续传的作用不见得能发挥到最大。今天介绍一个axel工具,开启多线程疯狂下载。 安装 Fedora/Cen...

linuxprobe16
27分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部