观察者模式与装饰者模式相遇的那些事

来源:互联网 发布:c 编程软件 编辑:程序博客网 时间:2024/05/16 14:43

一、题目与分析

题目:某企业准备研制一款带双屏幕显示的智能读卡器,该读卡器可以读取磁盘里的任一文件,并按照设定的读取模式在屏幕上显示。该读卡器有两种读取模式:一种小写模式,另一种倒序模式。
假设设定:
1、屏幕一只能按照信息小写模式的方式显示;屏幕二只能按照信息倒序模式的方式显示。
已知磁盘的文件名:MyFile.txt内容:
I KNOW YOU ARE STUDYING DESIGN PATTERNS.
2、屏幕一和屏幕二采取PULL方式获得信息。

请用正确的设计模式将上述需求设计出来并实现运行。

题目解读:如何从题目中抽取分析出该使用什么设计模式才能更好的解决需求呢?首先从题目入手,抽取题目关键字,智能读卡器,小写模式,倒序模式,屏幕一,屏幕二。然后把关键字的关系理清楚,屏幕一只能用小写模式显示信息,屏幕二只能用倒序模式显示信息,而小写模式和倒序模式是读卡器的功能。设计模式都是套路的,但是如何把这些套路如何来解决生活中的实际问题,就是我们需要掌握这些设计模式的理论知识。

下面是我设计的类图
这里写图片描述

首先把观察者和主题抽象类编写,然后屏幕一、屏幕二是具体观察者,具体主题只有一个是智能读卡器类,小写模式,倒序模式是工具类。把需求分析之后就开始编写类图,最后开始编码。

二、具体实现

1、主题抽象类Subject

public interface Subject { public void registerObserver(Observer o); public void removeObserver(Observer o); public void notifyObservers();}

2、具体主题类CardReaderSubject

public class CardReaderSubject implements Subject{    private ArrayList<Observer> observers;    private String path;    private String value;    public CardReaderSubject(){        observers=new ArrayList<Observer>();    }    @Override    public void registerObserver(Observer o) {        observers.add(o);    }    @Override    public void removeObserver(Observer o) {        int i=observers.indexOf(o);        if(i>=0){            observers.remove(o);        }    }    @Override    public void notifyObservers() {         for(int i=0;i<observers.size();i++){             Observer observer=(Observer)observers.get(i);             if(observer instanceof ScreenOneObserver){                 int c=0;                 String str="";                 try{                       InputStream in=new LowerCaseInputStream(new BufferedInputStream(new FileInputStream(path)));                          while((c=in.read())>=0){                                   str+=(char)c;                   }                   in.close();                   }catch(IOException e){                       e.printStackTrace();                   }                    value=str;             }             if(observer instanceof ScreenTwoObserver){                 int c=0;                 String str="";                 try{                       InputStream in=new InvertedOrderInputStream(new BufferedInputStream(new FileInputStream(path)));                    //c=0时,是把数据push进stack中,c大于0时就是pop数据出栈                       while((c=in.read())>=0){                       if(c!=0){                          str+=(char)c;                       }                   }                   in.close();                   }catch(IOException e){                       e.printStackTrace();                   }                    value=str;             }             observer.update(this);         }      }   public void measurementsChanged(){       notifyObservers();   }   public void setMeasurements(String path){       this.path=path;     measurementsChanged();   }   //提供观察者拉数据方法   public String getValue(){       return value;   }}

3、观察者类Observer

public interface Observer {public void update(Subject subject);}

4、屏幕一类ScreenOneObserver

public class ScreenOneObserver implements Observer{       private Subject cardReaderSubject;        private String value;    public ScreenOneObserver(Subject cardReaderSubject){        this.cardReaderSubject=cardReaderSubject;        cardReaderSubject.registerObserver(this);    }    @Override    public void update(Subject subject) {        CardReaderSubject cr=(CardReaderSubject)subject;        value=cr.getValue();    //拉数据        System.out.println(value);    }}

5、 屏幕二类ScreenTwoObserver

public class ScreenTwoObserver implements Observer{    private Subject cardReaderSubject;    private String value;    public ScreenTwoObserver(Subject cardReaderSubject){        this.cardReaderSubject=cardReaderSubject;        cardReaderSubject.registerObserver(this);    }    @Override    public void update(Subject subject) {        CardReaderSubject cr=(CardReaderSubject)subject;        this.value=cr.getValue();    //拉数据        System.out.println(value);    }}

6、 倒序模式类InvertedOrderInputStream

public class InvertedOrderInputStream extends FilterInputStream{    private List<Integer> stack=new ArrayList<Integer>();    private int result=0;    public InvertedOrderInputStream(InputStream in) {        super(in);    }    public int read() throws IOException{        int c;        if((c=super.read())>=0){        stack.add(0,c);        return result;        }        if(stack.size()>0){           result=stack.get(0);           stack.remove(0);           return result;          }else{        return -1;        }    }    public int read(byte[] b,int offset,int len)throws IOException{        int result=super.read(b, offset, len);        for(int i=offset;i<offset+result;i++){            b[i]=(byte)Character.toUpperCase((char)b[i]);        }        return result;    }}

7、小写模式类LowerCaseInputStream

public class LowerCaseInputStream extends FilterInputStream{

protected LowerCaseInputStream(InputStream in) {    super(in);}public int read() throws IOException{    int c=super.read();    return (c==-1?c:Character.toLowerCase((char)c));}public int read(byte[] b,int offset,int len)throws IOException{    int result=super.read(b, offset, len);    for(int i=offset;i<offset+result;i++){        b[i]=(byte)Character.toLowerCase((char)b[i]);    }    return result;}

}
8、测试类Main

public class Main {  public static void main(String[] args){      //选择的读取文件的路径      String path="e:\\test.txt";      CardReaderSubject cr=new CardReaderSubject();      ScreenOneObserver so=new ScreenOneObserver(cr);      ScreenTwoObserver st=new ScreenTwoObserver(cr);      cr.setMeasurements(path);  }}

9、效果图
这里写图片描述

三、具体分析思路

这里写图片描述

可能一开始你会有很多的疑问,为什么会采用观察者模式和装饰者模式。采用装饰者模式是为了把读卡器的小写模式和倒序模式都通过继承FilterInputStream类,就可以把从文件读取的信息封装起来。供CardReaderSubject类使用。采用观察者模式是为了把智能读卡器内判断遇到屏幕一或屏幕二时,把他们订阅到Main主题对象中,然后就能动态监听遇到不同屏幕采用相应的读卡器读取模式。