(java)从零开始之--装饰者设计模式
装饰者设计模式:
简单定义:增强一个类的功能,而且还可以让这些装饰类互相装饰。
应用场景:当要在某个功能的基础上扩充功能,并且扩充的功能具有大量排列组合,通过继承关系会衍生出大量子类,这时候用装饰者模式来解决。
装饰者设计模式的步骤:
1. 在装饰类的内部维护一个被装饰类的引用。
2. 让装饰类有一个共同的父类或者是父接口。
例如:人有一种行为叫“吃水果”,其中水果有4种:苹果、香蕉、鸭梨、橘子
现在有需求如下:
A类人行为:吃苹果
B类人行为:先吃苹果,再吃香蕉
C类人行为:先吃香蕉,再吃苹果
D类人行为:先吃橘子,后吃鸭梨
我们先用子类继承来实现:代码如下
interface IEatFruit{
public void eatFruit();
}
class PersonA implements IEatFruit{
@Override
public void eatFruit() {
System.out.println("吃苹果");
}
}
class PersonB implements IEatFruit{
@Override
public void eatFruit() {
System.out.println("吃苹果");
System.out.println("吃香蕉");
}
}
class PersonC implements IEatFruit{
@Override
public void eatFruit() {
System.out.println("吃香蕉");
System.out.println("吃苹果");
}
}
class PersonD implements IEatFruit{
@Override
public void eatFruit() {
System.out.println("吃橘子");
System.out.println("吃鸭梨");
}
}
这样当然是没问题的,每一类人对应new出来的对象 都可以实现对应的需求。
但是,当需求改为:
某类人行为:吃上面四种水果,并且要求有先后顺序
这样的排列组合有24种....
这样你还会用继承去做吗?写24个子类去实现接口,明显不合适。
这时候如果用到装饰者模式,代码则会变成:
interface IEatFruit{
public void eatFruit();
}
class PersonA implements IEatFruit{
IEatFruit eat;
public PersonA(){
this.eat = this;
}
public PersonA(IEatFruit _eat){
this.eat = _eat;
}
@Override
public void eatFruit() {
if(!(this.eat instanceof PersonA)){
this.eat.eatFruit();
System.out.println("吃苹果");
}else{
System.out.println("吃苹果");
}
}
}
class PersonB implements IEatFruit{
IEatFruit eat;
public PersonB(){
this.eat = this;
}
public PersonB(IEatFruit _eat){
this.eat = _eat;
}
@Override
public void eatFruit() {
if(!(this.eat instanceof PersonB)){
this.eat.eatFruit();
System.out.println("吃香蕉");
}else{
System.out.println("吃香蕉");
}
}
}
class PersonC implements IEatFruit{
IEatFruit eat;
public PersonC(){
this.eat = this;
}
public PersonC(IEatFruit _eat){
this.eat = _eat;
}
@Override
public void eatFruit() {
if(!(this.eat instanceof PersonC)){
this.eat.eatFruit();
System.out.println("吃鸭梨");
}else{
System.out.println("吃鸭梨");
}
}
}
class PersonD implements IEatFruit{
IEatFruit eat;
public PersonD(){
this.eat = this;
}
public PersonD(IEatFruit _eat){
this.eat = _eat;
}
@Override
public void eatFruit() {
if(!(this.eat instanceof PersonD)){
this.eat.eatFruit();
System.out.println("吃橘子");
}else{
System.out.println("吃橘子");
}
}
}
public class Demo2 {
public static void main(String[] args) {
//这样就可以通过上述4类人来相互装饰,就可以随意任意一种组合“吃水果”
//如:吃橘子->吃苹果
PersonD d = new PersonD();
PersonA a = new PersonA(d);
a.eatFruit();
System.out.println("-------我是分割线------------");
//如:吃苹果->吃橘子->吃鸭梨->吃香蕉
PersonA a2 = new PersonA();
PersonD d2 = new PersonD(a2);
PersonC c2 = new PersonC(d2);
PersonB b2 = new PersonB(c2);
b2.eatFruit();
}
}
输出结果如下:
吃橘子
吃苹果
-------我是分割线------------
吃苹果
吃橘子
吃鸭梨
吃香蕉
最后总结:
继承实现的增强类和修饰模式实现的增强类有何区别?
继承实现的增强类:
优点:代码结构清晰,而且实现简单.
缺点:对于每一个的需要增强的类都要创建具体的子类来帮助其增强,这样会导致
继承体系过于庞大。
装饰者模式实现的增强类:
优点:内部可以通过多态技术对多个需要增强的类进行增强, 可以使这些装饰类
达到互相装饰的效果。使用比较灵活。
缺点:需要内部通过多态维护需要被增强的类的实例。进而使得代码稍微复杂
(java)从零开始之--装饰者设计模式的更多相关文章
- 装饰器设计模式初探及Java中实际应用举例
本篇随笔主要介绍用Java实现简单的装饰器设计模式: 先来看一下装饰器设计模式的类图: 从图中可以看到,我们可以装饰Component接口的任何实现类,而这些实现类也包括了装饰器本身,装饰器本身也可 ...
- 42、Java装饰者设计模式
设计模式简介 什么是设计模式?设计模式是可以重复利用的解决方案.软件开发的先驱或者前辈们将之前在开发中遇到的问题进行总结并给出了解决方案,后辈在遇到这些问题之后直接使用这些方案即可解决问题.比如盖高楼 ...
- Java的几种常用设计模式
何为设计模式? 就是对一些常见问题进行归纳总结,并针对具体问题给出一套通用的解决办法(强调的是解决问题的思想): 在开发中,只要遇到这类问题,就可以直接使用这些设计模式解决问题. ---------- ...
- 用过滤器和装饰者设计模式(静态代理)解决getParameter乱码问题
post的乱码问题比较好解决,这里主要是对get请求的乱码做处理 解决思路:增强request对象的getParameter方法,使之 getParameter 直接获取到的就是解决乱码后的数据 有 ...
- 设计模式--装饰者设计模式(Decorator)
装饰者模式又叫包装模式. 通过另一个对象来扩展自己的行为,在不破坏类的封装的情况下,实现松耦合,易扩展的效果. 抽象组件角色: 一个抽象接口,是被装饰类和装饰类的父接口可以给这些对象动态地添加职责 ...
- Java中InputStream装饰器模式的大家族
本文写在po主初学JAVA时,在学习inputStream摸不着头脑,受Java IO-InputStream家族 -装饰者模式一文启发,所以在理清思路时写下本文.因为初学,如有错误,望指正. 因为和 ...
- Java成神路上之设计模式系列教程之一
Java成神路上之设计模式系列教程之一 千锋-Feri 在Java工程师的日常中,是否遇到过如下问题: Java 中什么叫单例设计模式?请用Java 写出线程安全的单例模式? 什么是设计模式?你是否在 ...
- java基础47 装饰着模式设计
1.装饰者模式 增强一个类的功能,而且还可以让这些装饰类相互装饰 2.装饰者设计模式的步骤 1.在装饰类的内部维护一个被装饰类的引用 2.让装饰者有一个共同的父类或者父接口 3.实例 packa ...
- java架构之路-(设计模式)五种创建型模式之单例模式
设计模式自身一直不是很了解,但其实我们时刻都在使用这些设计模式的,java有23种设计模式和6大原则. 设计模式是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了可 ...
随机推荐
- 队爷的新书 CH Round #59 - OrzCC杯NOIP模拟赛day1
题目:http://ch.ezoj.tk/contest/CH%20Round%20%2359%20-%20OrzCC杯NOIP模拟赛day1/队爷的新书 题解:看到这题就想到了 poetize 的封 ...
- (转载)Mysql查找如何判断字段是否包含某个字符串
(转载)http://www.th7.cn/db/mysql/201306/31159.shtml 有这样一个需求,在Mysql数据库字符串字段(权限)中,用户有多个不同的邮箱,分别被‘,’分开,现在 ...
- [CA]一个证书两个域名
一般一个证书是绑定一个Common name,出于某种测试的需要,我们可能要求一个Site的证书可以是针对2个域名的. 操作如下: 1.CA上CMD输入下面命令,回车: Certutil –setre ...
- vijosP1195“非常男女”计划
vijosP1195“非常男女”计划 链接:https://vijos.org/p/1195 [思路] 人数差. 人数差相等的两点之间的区间一定有男女人数相等. 计目前为止到i的1为sum1,0为su ...
- C#中同时使用Lambda表达式和递归
Func<object, int> RTFunc = (RTFuncRT) => { return (RTFuncRT as Func<object, int>)(RTF ...
- Apache-POI操作Excel的一些小技巧
Apache-POI操作Excel将合并后的单元格全部填充为相同数据的一个实例. private static void fillMergedRegion(final Sheet sheet) { f ...
- ERROR 2003 (HY000): Can't connect to MySQL server on 'ip'(111)
问题描述: 从一台linux远程连接另一台linux上的MySQL, 出现ERROR 2003 (HY000): Can't connect to MySQL server on 'ip'(111) ...
- PHP小题目 求 1*3+5*7+…+97*99的值
下面是另外两种比较基础的方法实现的代码
- c#基础语言编程-Path和Directory
引言 在程序常会对文件操作,在对文件操作中需要对文件路径的进行定位,在.Net中针对寻找文件提供两个静态类以供调用,Path和Directory. Path类 来自命名空间SYstem.IO,Path ...
- android 27 ListView
效果: 上图中ArrarAdapter是数组的适配器,CursorAdapter是游标适配器,用于操作数据库的数据. ListView是垂直列表,数据源是集合或者数组,这些View都是安卓里的Adap ...