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

有个大神写的很好:

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

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

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

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

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

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

参考: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,一经查实,立即删除!

相关文章

DQL、DML、DDL、DCL的概念与区别

http://blog.csdn.net/tomatofly/article/details/5949070 SQL语言的分类 SQL语言共分为四大类&#xff1a;数据查询语言DQL&#xff08;Data Query Language&#xff09;&#xff0c;数据操纵语言DML&#xff0c;数据定义语言DDL(Data Definition Language)&#xff0c;数据…

python学习总结

1.python环境搭建方便&#xff0c;只需要安装python解释器 2.python把任意数据类型赋值给变量&#xff0c;不用定义类型 3.Python的整数浮点数没有大小限制&#xff0c;不用担心超过数值范围。比如java的 int&#xff0c;long 4.python自带最常用的list列表和dicitonary字典&am…

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

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

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

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

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

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

ubuntu 常用软件和命令

永久修改屏幕的分辨率   sudo gedit .profile 将下面的四句话加入。.profile文件的最后   cvt 1280 768   xrandr --newmode "1280x768_60.00" 79.50 1280 1344 1472 1664 768 771 781 798 -hsync vsync   xrandr --addmode Virtual1 "1280x768_60.00&q…

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…

C语言 位操作简析

位运算 前面介绍的各种运算都是以字节作为最基本位进行的。 但在很多系统程序中常要求在位(bit)一级进行运算或处理。&#xff23;语言提供了位运算的功能&#xff0c; 这使得&#xff23;语言也能像汇编语言一样用来编写系统程序。 一、位运算符&#xff23;语言提供了六种位运…

算法:输入一个链表,输出该链表中倒数第k个结点。

算法&#xff1a;输入一个链表&#xff0c;输出该链表中倒数第k个结点。《剑指offer》 思路加到注释里面了&#xff1b; 1&#xff1a;两个if判断是否返回值为空&#xff0c;首个为空&#xff0c;没有第k个值&#xff1b; 2&#xff1a;for循环找到倒数第k个值&#xff0c;返回…

Spring事务那些事儿

&#xff08;一&#xff09;事务的隔离级别 大家都知道事务有四个属性&#xff0c;即ACID&#xff08;原子性、一致性、隔离性、持久性&#xff09;。这四个里面稍微难理解点的是一致性和持久性。所谓的一致性是指&#xff1a;事务执行前后数据的一致性状态&#xff0c;例如事…

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 …

scanf 用法大全

关于标准库函数scanf论坛上很多人对scanf的不太了解&#xff0c;导致程序出错&#xff0c;我想把scanf的具体用法贴出来&#xff0c;希望大家可以共同进步&#xff0c;有什么不对的地方可以提出来。int scanf(char *format&#xff0c;...);这应该是scanf的标准形式。先说说关于…

深入了解Spring IoC

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

软文营销实战记录

最近拜读了徐茂权老师的《 网络营销决胜武器(第2版)》&#xff0c;下面会梳理书中的内容&#xff0c;记录下以后可能会用到的软文营销的技巧。 一、软文载体 1、平面媒体软文&#xff1a;报纸、期刊。 2、非正式出版的基于印刷、打印形式载体的软文&#xff1a;企业印刷的宣传册…

oracle中rownum和row_number()的区别

见&#xff1a;http://www.jb51.net/article/65960.htm row_number()over(partition by col1 order by col2)表示根据col1分组&#xff0c;在分组内部根据col2排序&#xff0c;而此函数计算的值就表示每组内部排序后的顺序编号&#xff08;组内连续的唯一的&#xff09;。 与ro…

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…

day10-列表生成式

列表生成式即List Comprehensions&#xff0c;是Python内置的非常简单却强大的可以用来创建list的生成式。 1、生成一个列表 a [i for i in range(1,100) if i%21]print(list(a))或print(a)[1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, …

jrebel、JavaRebel

见&#xff1a;https://baike.baidu.com/item/jrebel/1115725?fraladdin JRebel是一套JavaEE开发工具。中文名jrebel属 性JavaEE开发工具资 费收费软件作 用Jrebel 可快速实现热部署JRebel是一套JavaEE开发工具。JRebel允许开发团队在有限的时间内完成更多的任务修正…