策略模式、观察者模式、代理模式、装饰模式 应用场景和实现

有个大神写的很好:

参考:设计模式学习笔记(四:策略模式)

参考:设计模式学习笔记(二:观察者模式)

参考:设计模式学习笔记-代理模式

参考:设计模式--装饰者模式与代理模式(重要)

参考:设计模式——代理模式与装饰模式的异同 (重要)

参考:设计模式之装饰模式

参考:java模式—装饰者模式

参考:修饰者模式(装饰者模式,Decoration)

一、策略模式:
 (1)解决场景:
某个功能有多个方案可以实现,要达到某个目的,需要根据具体的实际情况,选择合适的方法,
 (2)如何实现:
分为两个层次
 (a) 环境类
 环境类负责接收用户的请求,并根据实际情况把相应的请求委托给一组策略类中的一个;

 (b) 一组策略类
  一组封装了具体的实现类的算法,并负责具体的计算过程

(3)关键类图:

 

 首先定义策略类的接口: 

public interface GameStrategy {public void goldCoin();}

其次 实现一组策略类:

public class normalStrategy implements GameStrategy {   @Override                                           public void goldCoin() {                            //                                              System.out.println("普通玩家没有折扣");                 }                                                   
}       public class advancedStrategy implements GameStrategy {@Overridepublic void goldCoin() {// TODO Auto-generated method stubSystem.out.println("高级会员9折优惠");}
}

环境类的实现:

public class Context {                                //持有一个Strategy的引用                                   private GameStrategy mGameStrategy;               // 构造函数                                           public Context(GameStrategy strategy) {           this.mGameStrategy = strategy;                }                                                 public void setStrategy(GameStrategy strategy) {  this.mGameStrategy = strategy;                }                                                 public void goldCoin() {                          this.mGameStrategy.goldCoin();                }                                                 
}        

最后根据不同的情况进行调用:

public class main {                                          public static void main(String[] args) {                 //普通玩家策略                                             Context context = new Context(new normalStrategy()); context.goldCoin();                                  //高级玩家策略                                             context.setStrategy(new advancedStrategy());         context.goldCoin();                                 }                                                        
}   

 二、观察者模式

(1)解决场景:
  (a) 对一个对象状态的更新,需要其他对象同步更新
  (b) 对象仅需要将自己的更新通知给其他对象而不需要知道其他对象的细节
观察者模式,又称为发布订阅模式,它的特点:
  (a) subject 和 observer之间是松耦合的,各自独立实现,
  (b) subject在发送广播通知的时候,不需要指定具体的observer,observer可以自行决定是否要订阅
  (c) 遵循常用设计原则:高内聚,低耦合
(2)如何实现:

关键类图:

 定义观察者接口: 

public interface Observer {void update(String message,String name);}

实现观察者:

                                                                  
public class Bianyi1 implements Observer {                             //定义姓名                                                             private String bname = "张昊天";                                      @Override                                                          public void update(String message,String name) {                   System.out.println(bname+":"+name+"那里有新情况:"+ message);         }                                                                  
}                                                                     public class Bianyi2 implements Observer {                             //定义姓名                                                             private String bname = "石破天";                                      @Override                                                          public void update(String message,String name) {                   System.out.println(bname+":"+name+"那里有新情况:"+ message);         }                                                                  
}   

定义目标接口:

public interface Huairen {                  //添加便衣观察者                               void addObserver(Observer observer);    //移除便衣观察者                               void removeObserver(Observer observer); //通知观察者                                 void notice(String message);            
} 

两个实现目标的类:

import java.util.*;                                                          
/**                                                                          * 嫌犯大熊                                                                      */                                                                          
public class XianFan1 implements Huairen {                                   //别称                                                                     private String name = "大熊";                                              //定义观察者集合                                                                private List<Observer> observerList = new ArrayList<Observer>();         //增加观察者                                                                  
    @Override                                                                public void addObserver(Observer observer) {                             if(!observerList.contains(observer)){                                observerList.add(observer);                                      }                                                                    }                                                                        //移除观察者                                                                  
    @Override                                                                public void removeObserver(Observer observer) {                          if(observerList.contains(observer)){                                 observerList.remove(observer);                                   }                                                                    }                                                                        //通知观察者                                                                  
    @Override                                                                public void notice(String message) {                                     for(Observer observer:observerList){                                 observer.update(message,name);                                   }                                                                    }                                                                        
}                                                                            import java.util.*;                                                          
/**                                                                          * 嫌犯黑狗                                                                      */                                                                          
public class XianFan2 implements Huairen {                                   //别称                                                                     private String name = "黑狗";                                              //定义观察者集合                                                                private List<Observer> observerList = new ArrayList<Observer>();         //增加观察者                                                                  
    @Override                                                                public void addObserver(Observer observer) {                             if(!observerList.contains(observer)){                                observerList.add(observer);                                      }                                                                    }                                                                        //移除观察者                                                                  
    @Override                                                                public void removeObserver(Observer observer) {                          if(observerList.contains(observer)){                                 observerList.remove(observer);                                   }                                                                    }                                                                        //通知观察者                                                                  
    @Override                                                                public void notice(String message) {                                     for(Observer observer:observerList){                                 observer.update(message,name);                                   }                                                                    }                                                                        
}  

观察者根据目标进行调用:

public class Clienter {                           public static void main(String[] args) {      //定义两个嫌犯                                  Huairen xf1 = new XianFan1();             Huairen xf2 = new XianFan2();             //定义三个观察便衣警察                              Observer o1 = new Bianyi1();              Observer o2 = new Bianyi2();          //为嫌犯增加观察便衣                               
        xf1.addObserver(o1);                      xf1.addObserver(o2);                      xf2.addObserver(o1);                      xf2.addObserver(o3);                      //定义嫌犯1的情况                                String message1 = "又卖了一批货";               String message2 = "老大要下来视察了";             xf1.notice(message1);                     xf2.notice(message2);                     }                                             
}       

 

三、代理模式:


(1)解决场景:
    (a) 当我们想要隐藏某个类时,可以为其提供代理类

  (b) 当一个类需要对不同的调用者提供不同的调用权限时,可以使用代理类来实现

  (c) 当我们要扩展某个类的某个功能时,可以使用代理模式,在代理类中进行简单扩展
(2) 如何实现:
  (a) 代理类与委托类实现同一接口
  (b) 在委托类中实现功能,在代理类的方法中中引用委托类的同名方法
  (c) 外部类调用委托类某个方法时,直接以接口指向代理类的实例,这正是代理的意义所在:屏蔽。

(3) 类图:

 (a) 抽象的主题:

public interface Moveable {void move()  throws Exception;
}

(b)真实主题:

public class Car implements Moveable {public void move() throws Exception {Thread.sleep(new Random().nextInt(1000));System.out.println("汽车行驶中…");}
}

(c) 事务处理器:

public class TimeHandler implements InvocationHandler {private Object target;public TimeHandler(Object target) {super();this.target = target;}/*** 参数:*proxy 被代理的对象*method 被代理对象的方法*args 方法的参数* 返回:*Object 方法返回值*/public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {long startTime = System.currentTimeMillis();System.out.println("汽车开始行驶…");method.invoke(target, args);long stopTime = System.currentTimeMillis();System.out.println("汽车结束行驶…汽车行驶时间:" + (stopTime - startTime) + "毫秒!");return null;}}

(d) 调用:

public class Test {public static void main(String[] args) throws Exception{Car car = new Car();InvocationHandler h = new TimeHandler(car);Class<?> cls = car.getClass();/***loader 类加载器*interfaces 实现接口*h InvocationHandler*/Moveable m = (Moveable) Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(), h);m.move();}

 四、装饰模式:

装饰者(decorator)模式:在不改变对象自身的基础上,在程序运行期间给对像动态的添加职责。与继承相比,装饰者是一种更轻便灵活的做法。
装饰者模式的特点
可以动态的给某个对象添加额外的职责,而不会影响从这个类中派生的其它对象;

(1)应用场景:

(a)在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。

  (b)  需要动态地给一个对象增加功能,这些功能也可以动态地被撤销。  当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时。

(2)实现的例子:

最常见的就是输入输出流:

 BufferedReader in1 = new BufferedReader(new InputStreamReader(new FileInputStream(file)));//字符流DataInputStream in2 = new DataInputStream(new BufferedInputStream(new FileInputStream(file)));//字节流// DataInputStream-从数据流读取字节,并将它们装换为正确的基本类型值或字符串// BufferedInputStream-可以通过减少读写次数来提高输入和输出的速度

 

从例子开始讲解,比如今天你要出门约会,你肯定是要决定好你要穿什么样的衣服出门,用衣服来装饰下自己,让自己拥有一个完美的约会。比如,你会穿一件衬衫,然后穿一件西服裤,最后穿皮鞋出门。这就是装饰者模式的一个例子。为了实现这个功能,会有下面的代码。
public class People {public void wearShirt(){System.out.println("******穿衬衫******");}
public void wearTrouser(){System.out.println("******穿西服裤******");}public void wearShoes(){System.out.println("******穿皮鞋******");}}

 

 
public class Client { 
public static void main(String[] args) {People people = new People();people.wearShirt();people.wearTrouser();people.wearShoes();} 
}

 

虽然上面的代码实现了出门穿衣服的功能,但是这里会问题。如果我现在要增加一个功能,我要先穿袜子,再穿皮鞋。此时就要在People类中增加一个穿袜子的方法。这就违背了设计模式的开闭原则,所谓开闭原则就是类可以进行扩展,但是不可以进行修改。所以就有如下的设计:
public interface People {
public void wearClothing(); 
}
public class Xiaoming implements People{ 
private String name; 
public Xiaoming(){name = "小明";} 
public void wearClothing(){System.out.println(name+"******开始穿衣服******");}public String getName() {return name;}}
public abstract class Finery implements People { 
protected People people; 
public Finery(People people){this.people = people;}public abstract void wearClothing();}
public class ShirtFinery extends Finery {public ShirtFinery(People people){super(people);}@Overridepublic void wearClothing() {people.wearClothing();System.out.println("******穿衬衫******");} }
public class ShoesFinery extends Finery { 
public ShoesFinery(People people){super(people);}@Overridepublic void wearClothing() {people.wearClothing();System.out.println("******穿皮鞋*******");} 
}public class TrouserFinery extends Finery {public TrouserFinery(People people){super(people);}@Overridepublic void wearClothing() {people.wearClothing();System.out.println("******穿西服裤*******");} 
}
public class Client { public static void main(String[] args) {People people = new Xiaoming();Finery shirtFinery = new ShirtFinery(people);Finery trouserFinery = new TrouserFinery(shirtFinery);Finery shoesFinery = new ShoesFinery(trouserFinery);shoesFinery.wearClothing();}}

  (3)类图:

People是定义了一个接口,用来添加具体的职责,而Xiaoming是具体的People,也就是被装饰的对象。对于Finery实现了People接口,进而对People进行扩展,而Finery的子类就是具体的装饰类,Finery中依赖People类,装饰的具体对象。 这就是所谓的装饰者模式。如果我要添加穿袜子的步骤,则只需要再添加一个实现类,完全不需要修改其他代码(Client是客户端类,肯定是要修改的)。

 

装饰者模式和代理模式的区别:

两种模式的特点


装饰模式:

  在不改变接口的前提下,动态扩展对象的访问。
  动态继承,让类具有在运行期改变行为的能力。
  装饰模式,突出的是运行期增加行为,这和继承是不同的,继承是在编译期增加行为。
  强调:增强,新增行为

代理模式:

  在不改变接口的前提下,控制对象的访问。
  1.从封装的角度讲,是为了解决类与类之间相互调用而由此导致的耦合关系,可以说是接口的另外一个层引用。
    比如:在a类->b代理->c类这个关系中,c类的一切行为都隐藏在b中。即调用者不知道要访问的内容与代理了什么对象。
  2.从复用的角度讲,可以解决不同类调用一个复杂类时,仅仅因较小的改变而导致整个复杂类新建一个类。
    比如:a类->c类1;b类->c类2。
    可以变为a类->ca代理类->c类;b类->cb代理类-c类。
  代理模式,是类之间的封装和(某方面的)复用。
  强调:限制,控制访问

 

总结:

  1. 装饰模式可以让使用者直观的看到增强了哪些功能,而代理模式完全限制了使用者。

  2. 对装饰模式来说,装饰者(Decorator)和被装饰者(Cafe)都实现同一个 接口。

  3. 对代理模式来说,代理类(Proxy Class)和真实处理的类(Real Class)都实现同一个接口。

  4. 此外,不论我们使用哪一个模式,都可以很容易地在真实对象的方法前面或者后面加上自定义的方法。

装饰模式与继承的比较


  明显的,装饰模式可以动态的扩展对象的行为。

  比如某对象有30项行为,但是在第一阶段用到1-20行为,第二阶段用到11-30项行为,所以这时候,就可以只定义11-20的行为。

  在第一阶段运行时,可以将1-10的行为以“装饰1”给加上

  到第二阶段运行时,可以将“装饰1”去掉,将21-30的能以“装饰2”给加上。

  但是继承是在编译期增加行为。

装饰模式的优缺点


优点:

  1. 装饰模式可以提供比继承更多地灵活性。
  2. 可以通过一种动态的方式来扩展一个对象的功能,在运行时选择不同的装饰器,从而实现不同的行为。
  3. 通过使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出很多不同行为的组合。可以使用多个具体装饰类来装饰同一对象,得到功能更为强大的对象。
  4. 具体构件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构件类和具体装饰类,在使用时再对其进行组合,原有代码无须改变,符合“开闭原则”。

缺点:

  1. 会产生很多的小对象(具体装饰类),增加了系统的复杂性。
  2. 这种比继承更加灵活机动的特性,也同时意味着装饰模式比继承易于出错,排错也很困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为烦琐。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/450961.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

李国杰院士:国内开源社区的崛起需要一个过程

[CSDN.NET 付江/文]日前&#xff0c;在第二届“龙芯杯”中国开源软件设计大赛启动仪式上&#xff0c;CSDN记者专访了中国工程院院士、第三世界科学院院士李国杰。李国杰院士就国产基础软件现状、面临的机遇和挑战、开源环境以及生态系统建设等话题分享了自己的看法。 打造自主…

SuperMap iObject入门开发系列之五管线属性查询

本文是一位好友“托马斯”授权给我来发表的&#xff0c;介绍都是他的研究成果&#xff0c;在此&#xff0c;非常感谢。 管线属性查询功能针对单一管线图层进行特定的条件查询&#xff0c;然后将查询结果输出为列表&#xff0c;并添加点位闪烁功能&#xff0c;例如查询污水管线中…

三类基于贪心思想的区间覆盖问题

一、区间完全覆盖问题 问题描述&#xff1a;给定一个长度为m的区间&#xff0c;再给出n条线段的起点和终点&#xff08;注意这里是闭区间&#xff09;&#xff0c;求最少使用多少条线段可以将整个区间完全覆盖。 样例&#xff1a;一个长度为8的区间&#xff0c;可选的线段有[2,…

Eclipse搭建Android开发环境(安装ADT,Android4.4.2)

见&#xff1a;http://blog.csdn.net/zht666/article/details/29837777 使用Eclipse做Android开发&#xff0c;需要先在Eclipse上安装ADT&#xff08;Android Development Tools&#xff09;插件。 1.安装JDK 1.7 JDK官网http://www.oracle.com/technetwork/java/javase/downlo…

Silverlight Blend动画设计系列八:拖放(Drag-Drop)操作与拖放行为(DragBehavior)

Silverlight & Blend动画设计系列八&#xff1a;拖放(Drag-Drop)操作与拖放行为(DragBehavior) 原文:Silverlight & Blend动画设计系列八&#xff1a;拖放(Drag-Drop)操作与拖放行为(DragBehavior)在Silverlight中自身并没有提供拖放功能的相关实现&#xff0c;要实现拖…

mysql查询显示行号

见&#xff1a;http://blog.csdn.net/muzizhuben/article/details/49449853 使用mysql查询显示行号&#xff0c;没有像oracle这么方便。 不过也可以通过设定变量显示行号&#xff0c;例如&#xff1a; -- 生成 行号 select r:r1 as rowno , a.* from my_tb a ,(select r:0) b …

深入了解Spring IoC

IoC全称Inversion of Control即控制反转&#xff0c;它还有一个别名依赖注入。spring利用Ioc容器帮我们自动构建对象及注入依赖对象&#xff0c;减少了对象构建与业务代码的耦合&#xff0c;使得我们能够更加高效愉快的写bug&#x1f41e;了(&#xffe3;▽&#xffe3;)"…

java类加载顺序

在java中类的加载、初始化都是在程序运行期完成的&#xff0c;虽然会稍微增加开销&#xff0c;但是却很大的增加了灵活性&#xff0c;我们可用在运行期间动态的去网络或其他地方加载一个二进制流来作为程序代码的一部分。接下来我们简单介绍下java类加载过程。 从上图中我们可…

dealloc不调用的情况

2019独角兽企业重金招聘Python工程师标准>>> 1、没有停止定时器 - (void)dealloc { [_timer invalidate]; _timer nil; } 2、VC中有代理Delegate&#xff0c;需要设置delegate的时候&#xff0c;设置为weak property (nonatomic,weak) id<ZoeEatDe…

[MicroPython]stm32f407控制DS18B20检测温度

2019独角兽企业重金招聘Python工程师标准>>> 1.实验目的 1. 学习在PC机系统中扩展简单I/O 接口的方法。 2. 进一步学习编制数据输出程序的设计方法。 3. 学习DS18B20的接线方法&#xff0c;并利用DS18B20检测当前温度。 2.所需元器件 F407Micropython开发板…

Java中Web程序修改配置文件不重启服务器的方法

见&#xff1a;http://blog.sina.com.cn/s/blog_69398ed9010191jg.html 另&#xff1a;http://ekisstherain.iteye.com/blog/1701463 jrebel 、JavaRebel是什么&#xff0c;见另一博客&#xff1a;jrebel/JavaRebel 开发环境 1. JDK 2. MyEclipse 3. Tomcat 4. Struts2 5.…

一起唠唠分布式锁

&#xff08;1&#xff09;分布式锁和分布式事务的区别 1.分布式锁是在集群环境下&#xff0c;用来控制不同机器对全局共享资源的访问。 2.分布式事务是在集群环境下&#xff0c;用来保证全局事务的一致性&#xff0c;保证多个数据库的数据整体上能正确的从一个一致性状态转到…

DCT(离散余弦变换(DiscreteCosineTransform))

离散余弦变换&#xff08;Discrete Cosine Transform&#xff0c;简称DCT变换&#xff09;是一种与傅立叶变换紧密相关的数学运算。在傅立叶级数展开式中&#xff0c;如果被展开的函数是实偶函数&#xff0c;那么其傅立叶级数中只包含余弦项&#xff0c;再将其离散化可导出余弦…

从源码看ConcurrentHashMap

简介 ConcurrentHashMap是线程安全的HashMap实现&#xff0c;这里主要研究JDK8后的ConcurrentHashMap&#xff0c;下面是ConcurrentHashMap的简单结构&#xff1a; ConcurrentHashMap基于HashMap的基本逻辑&#xff0c;通过CAS synchronized 来保证并发安全性。ConcurrentHas…

Spring Boot 整合Mybatis (一)

2019独角兽企业重金招聘Python工程师标准>>> 新建spring-boot项目&#xff0c;相关依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><de…

x264 的 cache详解

在这里和下一级别的分析中有必要先讲一下这个h->mb.cache&#xff08;没法讲&#xff0c;就是cache!&#xff09;。 x264_macroblock_cache_load将参考帧中某位置的&#xff08;重建后&#xff09;数据保存进cache&#xff0c;供参考和反复使用。 x264_macroblock_cache_s…

Repeater的使用

1.页面代码 如果要分页&#xff0c;那么页面开头必须写&#xff08;<% Register Src"~/Controls/Page.ascx" TagName"Page" TagPrefix"uc1" %>&#xff09; 并且分页&#xff0c;页脚<uc1:Page ID"Page2" runat"server&…

Android NDK MediaCodec在ijkplayer中的实践

https://www.jianshu.com/p/41d3147a5e07 从API 21&#xff08;Android 5.0&#xff09;开始Android提供C层的NDK MediaCodec的接口。 Java MediaCodec是对NDK MediaCodec的封装&#xff0c;ijkplayer硬解通路一直使用的是Java MediaCodec接Surface的方式。 本文的主要内容是&a…

leetcode-49-字母异位词分组(神奇的哈希)

题目描述&#xff1a; 给定一个字符串数组&#xff0c;将字母异位词组合在一起。字母异位词指字母相同&#xff0c;但排列不同的字符串。 示例: 输入: ["eat", "tea", "tan", "ate", "nat", "bat"], 输出: [[&quo…

【精心总结】java内存模型和多线程必会知识

内存模型 &#xff08;1&#xff09;java内存模型到底是个啥子东西&#xff1f; java内存模型是java虚拟机规范定义的一种特定模型&#xff0c;用以屏蔽不同硬件和操作系统的内存访问差异&#xff0c;让java在不同平台中能达到一致的内存访问效果&#xff0c;是在特定的协议下…