黑马程序员技术交流社区

标题: 【广州校区】【原创】对Balking设计模式的初步认识 [打印本页]

作者: 瞧瞧嗨一波...    时间: 2018-11-1 13:25
标题: 【广州校区】【原创】对Balking设计模式的初步认识
Balking设计模式
针对Balking设计模式,我们先结合一下现实生活中的例子来认识一下它。我们在餐馆点餐,想好之后,举手示意服务员点菜,于是,看到我举手的服务员就向我走过来,但这时,另一位服务员也看到我举手示意了,但她看到已经有一位服务员走向了我,所以就没有再过来......
如果现在不适合执行这个操作,或者没必要执行这个操作,就停止处理,直接返回-----这就是我们介绍的Balking模式。
我们来看一下Balking模式的简单示例程序,这个程序会定期地将当前数据内容写入文件中。当数据内容被写入时,会完全覆盖上次写入的内容,只有最新的内容才会被保存。另外,当写入内容和上次写入的内容完全相同时,再向文件写入就显得多余了,所以就不再执行写入操作。也就是说,该程序以“数据内容存在不同”作为守护条件,如果数据内容相同,则不执行写入操作,直接返回(Balk)。
在这里我们来思考一下文本工具的“自动保存功能”,所谓自动保存功能,就是为了防止电脑突然死机,而定期地将数据保存到文本中的功能。下面该示例程序可以说是自动保存功能的超级精简版。
先介绍一下用到的一下类:Data表示可以修改并保存的数据的类,对应文本工具的文本内容;SaverThread定期保存数据的内容的类,对应的是执行自动保存的线程ChangerThread是模仿“进行文本修改并随时保存的用户”,对应着的是修改并保存数据内容的类
Data类用于表示当前数据。
filename字段是执行保存的文件名称
content字段是表示数据内容的字符串,也就是写入文件的内容。
changed字段用于表示自上次保存之后,Content字段是否又进行了修改,changed字段的值为true时表示进行了修改,为false则为未修改,程序根据changed的值决定要不要执行文件写入。这种表示两种状态的字段和变量,我们通常称之为(flag)。这里,“changed字段标志位true”便是守护条件。Data类中用于修改数据内容的方法(change),以及要求将数据内容保存到文件中的方法(save)。另外还有一个实际执行文件保存的方法(doSave)
change方法中,新的数据内容会被赋予到content字段,同时,changed字段会被设置为true,这表示内容进行了修改。
Changesave这两个方法都被声明了synchronized方法,我们都知道,当看到synchronized时我们需要思考一下在保护着什么,在这里,我们保护的是contentchanged字段。
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
public class Data {
        private final String filename; // 保存的文件名称
        private String content; // 数据内容
        private Boolean changed;// 修改后的文件尚未保存时,为true
        public Data(String filename, String content) {
                this.filename = filename;
                this.content = content;
                this.changed = true;
        }
        // 修改数据内容
        public synchronized void change(String newContent) {
                content = newContent;
                changed = true; //为了表示content字段内容与文件内容不一致,未修改状态
        }
        // 若数据内容修改过,则保存到文件中
        public synchronized void save() throws IOException {
                if (!changed) {
                        return;
                }
                doSave();
                changed = false; // 为了表示content字段内容与文件内容一致,未修改状态
        }
        private void doSave() throws IOException {
                System.out.println(Thread.currentThread().getName() + "calls doSave,content=" + content);
                Writer writer = new FileWriter(filename);
                writer.write(content);
                writer.close();
        }
}SaverThread类用于定期保存数据内容
run方法中每隔一秒就调用一次Data实例的save方法,如果文件操作发生错误,IOException异常被抛出,该线程就会终止运行。
import java.io.IOException;
import com.balking.pojo.Data;
public class SaverThread extends Thread{       
        private final Data data;
        public SaverThread(String name,Data data) {
                super(name);
                this.data = data;
        }
        public void run() {
                try {
                        while (true) {
                                data.save(); //要求保存数据
                                Thread.sleep(1000); //休眠约1                               
                        }
                } catch (IOException e) {
                        e.printStackTrace();
                } catch (InterruptedException e) {
                        e.printStackTrace();
                }
        }
}
ChangerThread类用于修改数据内容,并执行保存处理
启动的线程以”No.0”,”No.1”,”No.2”, ...字符串为参数,循环调用change方法来修改数据。每修改完一个数据,线程都会“执行点别的操作”(实际上只是使用了sleep方法随机暂停了一段时间),然后调用save方法保存数据。这用来表示“将刚才修改的数据反映到文件中”。
注意Data类的doSave方法每次都是重新创建文件。由于在重新创建之后,文件内容会全部消失,所以该该示例并不能直接用作应用程序的自动保存功能。实际上,实现自动保存功能时,文件必须要进行备份。
import java.io.IOException;
import java.util.Random;
import com.balking.pojo.Data;
public class ChangerThread extends Thread{
        private final Data data;
        private final Random  random = new Random();
       
        public ChangerThread(String name,Data data) {
                super(name);
                this.data = data;
        }
        public void run() {
                try {
                        for (int i = 0; true; i++) {
                                data.change("No."+i); //修改数据
                                Thread.sleep(random.nextInt(1000)); //执行其他操作
                                data.save();     //显示地保存
                        }
                } catch (InterruptedException e) {
                        e.printStackTrace();
                } catch (IOException e) {
                        e.printStackTrace();
                }
        }
       
}
Main类运行:两个线程都执行了doSave方法。
请注意:不管是哪种情况,content字段的内容都“不是重复保存的”(没有重复的编号),这是因为content内容相同时,线程就会Balk出,不再调用doSave方法。
import com.balking.pojo.Data;
import com.balking.thread.ChangerThread;
import com.balking.thread.SaverThread;
public class Main {       
        public static void main(String[] args) {
                Data data = new Data("data.txt","emtity");
                new ChangerThread("ChangerThread", data).start();
                new SaverThread("SaverThread",data).start();
        }
}
运行结果:
也可参考时序图:

这就是我们介绍的Balking模式---对象本身拥有状态,该对象只有在自身状态合适时才会执行处理,否则便不会执行处理。
我们首先将对象的合适状态表示为守护条件。然后再处理之前,检查守护条件是否成立,只有当守护条件成立时,对象才会继续执行处理,如果守护条件不成立,则不执行处理,立即从方法中返回。






欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2