(十六)状态模式(State)

最后更新于:2022-04-01 15:48:39

状态模式(State)就是根据对象的状态不同,将有不同的行为。很简单的方法我们可以做N个 ~~~ if(){ } else if(){ } ... ... else{ } ~~~ 但是这样可想而知工作量会相当的大,这样就引入了状态模式,能实现和前面一样的功能,但是没有判断语句,而且如果添加了新的功能模块或者是流程,只要添加一个状态类就可以了。下面是简单的状态模式的原理图: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-07-12_5784560a18132.gif) 这里我用了一个QQ登录的状态来简单的模拟了一下状态模式,因为QQ从离线到登录到忙碌到离线就是一个很好的状态模式: 简单的画了一个原理图: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-07-12_5784560a2bc34.gif) 首先建立一个state接口,主要用于实现用,通过接口编程方便: ~~~ package com.designpattern.state; public interface State { public void handle(QQ qq); } ~~~ 而后分别建立离线状态,Q我吧状态,忙碌状态,然后又回到离线,具体内容是一样的,就是一个状态里面的handle方法创建了下一个状态从而达到状态不断切换的功能: ~~~ package com.designpattern.state; public class LeavingState implements State { @Override public void handle(QQ qq) { qq.setState(new LoginningState()); System.out.println("QQ正在登陆在中······"); } } ~~~ ~~~ package com.designpattern.state; public class LoginningState implements State { @Override public void handle(QQ qq) { qq.setState(new ChattingState()); System.out.println("QQ登陆成功,Q我吧······"); } } ~~~ ~~~ package com.designpattern.state; public class ChattingState implements State { @Override public void handle(QQ qq) { qq.setState(new BusyingState()); System.out.println("QQ正在忙碌中······"); } } ~~~ ~~~ package com.designpattern.state; public class BusyingState implements State { @Override public void handle(QQ qq) { qq.setState(new LeavingState()); System.out.println("QQ已经离线······"); } } ~~~ 这样定义一个QQ类,主要是对QQ的各种状态的一个动态的变化,废话不多说,看代码就明了: ~~~ package com.designpattern.state; public class QQ { private State state; public QQ() { state = new LeavingState(); } public State getState() { return state; } public void setState(State state) { this.state = state; } public void handle() { state.handle(this); } } ~~~ 然后客户端调用输出: ~~~ package com.designpattern.state; public class Client { public static void main(String[] args) { QQ qq = new QQ(); qq.handle(); qq.handle(); qq.handle(); qq.handle(); qq.handle(); qq.handle(); qq.handle(); qq.handle(); } } ~~~ ~~~ QQ正在登陆在中······ QQ登陆成功,Q我吧······ QQ正在忙碌中······ QQ已经离线······ QQ正在登陆在中······ QQ登陆成功,Q我吧······ QQ正在忙碌中······ QQ已经离线······ ~~~ 这样就简单的模拟了QQ的一系列的状态; 状态模式使代码种复杂而庸长的逻辑判断语句问题得到了解决,而且具体状态角色将具体的状态和它对应的行为封装起来了,这使得增加一种新的状态变得十分简单。但是每一个状态对应一个具体的状态类,是结构分散,逻辑不是很清楚,阅读代码工作量会大一些。 看到这里我不禁思考了一个问题,既然用状态模式可以模拟QQ的一系列的状态,那么我的状态的改变也一样能通知好友,让好友时时的关注我的状态情况,这时我就想到了刚刚学到的Observer模式,就是一个观察啊,我就想了一下,把两个模式用到一起,把每一个状态的变化都通知自己所有的好友,不多说,马上做的Demo试试: 和上面一样首先建立了一个公用的接口State.java 接着模式QQ的四种状态,这里就粘贴了一个实例,不过都差不多: ~~~ package com.designpattern.state_observer; public class ChattingState implements State { @Override public void handle(QQ qq) { qq.setState(new BusyingState()); qq.setMessage("QQ正在忙碌中······"); } } ~~~ 和上面不同的是堕落一个setMessage,这里是用来传递给QQ类,这样才能再次提醒观察的QQ好友,我的变化; 这里QQ类我定义成了一个抽象的类,不过大部分都封装好了,在让子类去继承的时候就继承一个handle方法就能实现操作,这样看起来比较简单: ~~~ package com.designpattern.state_observer; import java.util.ArrayList; import java.util.List; public abstract class QQ { private List<Friends> friends = new ArrayList<Friends>(); private String message; private String name = "halberd"; private State state; public QQ() { this.state = new LeavingState(); } public synchronized QQ addFriend(Friends friend) { friends.add(friend); return this; } public String getMessage() { return message; } public State getState() { return state; } public QQ handle() { this.state.handle(this); System.out.println(this.message); this.notifyFriends(); return this; } public void notifyFriends() { for (int i = 0; i < friends.size(); i++) { Friends friend = (Friends) friends.get(i); friend.recevie(this.message, this.name); } } public synchronized QQ removeFriend(Friends friend) { friends.remove(friend); return this; } public void setMessage(String message) { this.message = message; } public void setState(State state) { this.state = state; } } ~~~ 其实很简单,就是把两个模式结合了一个,之后就是具体的实例对象: ~~~ package com.designpattern.state_observer; public class MyQQ extends QQ { @Override public QQ handle() { return super.handle(); } } ~~~ 我起名为MyQQ意为我的QQ,然后在用我的QQ好友实现Friends接口: ~~~ package com.designpattern.state_observer; public interface Friends { public void recevie(String message,String name); } ~~~ 里面的两个参数一个是状态,一个是用户名(其实一个不写也行,我是想如果观察的不是我,就又可以复用了) 然后定义了两个朋友: ~~~ package com.designpattern.state_observer; public class AndiMuise implements Friends { @Override public void recevie(String message, String name) { System.out.println("AndiMuise已经知道 " + name + " : " + message); } } ~~~ 客户端操作如下: ~~~ package com.designpattern.state_observer; public class Client { public static void main(String[] args) { QQ qq = new MyQQ(); qq.addFriend(new AndiMuise()).addFriend(new Steve()); qq.handle().handle().handle(); } } ~~~ 实例一个QQ对象,这里当然是我自己了,MyQQ这里如果是别人的直接再继承一下就行了,也不用修改代码,之后添加了两个QQ好友作为监听者,然后开始我一系列的状态的变化: ~~~ QQ正在登陆在中······ AndiMuise已经知道 halberd : QQ正在登陆在中······ Steve已经知道 halberd : QQ正在登陆在中······ QQ登陆成功,Q我吧······ AndiMuise已经知道 halberd : QQ登陆成功,Q我吧······ Steve已经知道 halberd : QQ登陆成功,Q我吧······ QQ正在忙碌中······ AndiMuise已经知道 halberd : QQ正在忙碌中······ Steve已经知道 halberd : QQ正在忙碌中······ ~~~ 这样就大功告成了,其实这样挺好的,慢慢学会把几个模式综合一下,因为重复的代码比较多,没有贴全,上传到了: [http://download.csdn.net/detail/wclxyn/4230476](http://download.csdn.net/detail/wclxyn/4230476) 初学笔记,还望批评指正 (后来改成了这个样子,就是能调用了setName方法,当然返回值是QQ,这样就省事了,关键是我比较懒) ~~~ package com.designpattern.state_observer; public class Client { public static void main(String[] args) { QQ qq = new MyQQ(); qq.setName("wclxyn").addFriend(new AndiMuise()).addFriend(new Steve()) .handle().handle().handle(); new MyQQ().setName("腾讯客服").addFriend(new AndiMuise()).addFriend( new Steve()).handle().handle().handle(); } } ~~~ ~~~ QQ正在登陆在中······ AndiMuise已经知道 wclxyn : QQ正在登陆在中······ Steve已经知道 wclxyn : QQ正在登陆在中······ QQ登陆成功,Q我吧······ AndiMuise已经知道 wclxyn : QQ登陆成功,Q我吧······ Steve已经知道 wclxyn : QQ登陆成功,Q我吧······ QQ正在忙碌中······ AndiMuise已经知道 wclxyn : QQ正在忙碌中······ Steve已经知道 wclxyn : QQ正在忙碌中······ QQ正在登陆在中······ AndiMuise已经知道 腾讯客服 : QQ正在登陆在中······ Steve已经知道 腾讯客服 : QQ正在登陆在中······ QQ登陆成功,Q我吧······ AndiMuise已经知道 腾讯客服 : QQ登陆成功,Q我吧······ Steve已经知道 腾讯客服 : QQ登陆成功,Q我吧······ QQ正在忙碌中······ AndiMuise已经知道 腾讯客服 : QQ正在忙碌中······ Steve已经知道 腾讯客服 : QQ正在忙碌中······ ~~~
';

(十五)观察者模式(Observer)

最后更新于:2022-04-01 15:48:37

观察者模式(Observer)就是定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都得到通知并被自动更新。 对于观察者模式的原理图: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-07-12_57845609e7d48.gif) 通过一个一个抽象的主题Subject保存了多个信息处理列表,可以添加多个观察者,实现即时的通知观察者最新动态然后分别派生子类对象对具体的消息和状态做出处理,下面我们联系到具体的问题:正好我还在读,就拿学校通知公告来举例子吧,学校发布一个公告,要通知学生,老师,保洁阿姨,和食堂等相应的通知,这样才能正常的进行工作,比如这次清明放假,要通知所有机关和单位做好准备,这样才能保证正常有序的进行,下面是简单的原理图和例子程序: 换了一个UML这次用的一个jude很好的简单实用,而且这个是免安装的 提供了一下下载地址 [http://download.csdn.net/detail/wclxyn/4226796](http://download.csdn.net/detail/wclxyn/4226796)(不需要财富值) 示例原理图(新手原理图不对之处请多多指教) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-07-12_5784560a05348.gif) 首先定义接口观察者,定义接受消息的方法,具体内容如下: ~~~ package com.designpattern.observer; public interface Observer { public void receive(String message); } ~~~ 然后分别写教师,学生,食堂,保洁观察者的实现类: ~~~ package com.designpattern.observer; public class Teachers implements Observer { @Override public void receive(String message) { System.out.println("教师收到" + message); } } ~~~ ~~~ package com.designpattern.observer; public class Students implements Observer { @Override public void receive(String message) { System.out.println("学生收到" + message); } } ~~~ ~~~ package com.designpattern.observer; public class Mess implements Observer { @Override public void receive(String message) { System.out.println("食堂收到" + message); } } ~~~ ~~~ package com.designpattern.observer; public class Cleaner implements Observer { @Override public void receive(String message) { System.out.println("保洁收到" + message); } } ~~~ 然后定义被观察者接口,具体这里是学校,定义了通知公告的方法announcement方法和提醒方法notifyReceive方法同时定义add和romove观察者的方法,这里用synchronized控制添加和移除,为了操作的便捷,定义返回值为School,这样能连续操作,如下: ~~~ office.addObserver(new Mess()).addObserver(new Students()).addObserver( new Teachers()).addObserver(new Cleaner()); ~~~ 具体的School如下: ~~~ package com.designpattern.observer; import java.util.ArrayList; import java.util.List; public abstract class School { private List<Observer> observers = new ArrayList<Observer>(); private String message; public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public void announcement() { notifyRecevie(); } public synchronized School addObserver(Observer observer) { observers.add(observer); return this; } public synchronized School removeObserver(Observer observer) { observers.remove(observer); return this; } public void notifyRecevie() { for (int i = 0; i < observers.size(); i++) { Observer observer = (Observer) observers.get(i); observer.receive(getMessage()); } } } ~~~ 然后具体的实例类Office进行具体的通知: ~~~ package com.designpattern.observer; public class Office extends School { @Override public void announcement() { System.out.println("政教处通知明天放假"); this.setMessage("明天放假"); super.announcement(); System.out.println("---------------------"); } } ~~~ 之后客户端调用: ~~~ package com.designpattern.observer; public class Client { public static void main(String[] args) { Office office = new Office(); office.addObserver(new Mess()).addObserver(new Students()).addObserver( new Teachers()).addObserver(new Cleaner()); office.announcement(); } } ~~~ 然后打印结果如下,如果动态的添加和移除观察者都能实现通知: ~~~ 政教处通知明天放假 食堂收到明天放假 学生收到明天放假 教师收到明天放假 保洁收到明天放假 --------------------- ~~~ 在java的API里面也封装好了这样一个观察者的接口 具体的实例时观察者继承Observer类,被观察者实现Observable接口然后调用其中的具体方法,操作很简单具体参见API就可以了,简单些了一个小Demo: ~~~ package wlzx.mh.observer; import java.util.Observable; public class House extends Observable { private float price; private String name; public String getName() { return name; } public House(float price) { this.price = price; } public String toString(){ return "House.java" ; } public float getPrice() { return price; } public void setName(String name) { this.name = name; super.setChanged(); super.notifyObservers(name); } public void setPrice(float price) { super.setChanged();// 通知内容已经可以被修改了 this.price = price; // 一旦修改,则表示价格改变,那么价格改变之后,实际上应该立刻通知所有的观察者 super.notifyObservers(price);// 通知所有的观察者已经改变 } } ~~~ ~~~ package wlzx.mh.observer; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Observable; import java.util.Observer; public class Person implements Observer { // arg表示改变之后的内容 // o表示观察的对象 public String getDateTime() { return (new SimpleDateFormat("yyyy-MM-dd hh:mm:ss.SSS") .format(new Date())).toString(); } public void update(Observable o, Object arg) { System.out.println(getDateTime() + "----" + o + "----" + arg); } } ~~~ ~~~ package wlzx.mh.observer; public class TestObserver { public static void main(String[] args) { House h = new House(3000.0f); Person per1 = new Person(); Person per2 = new Person(); Person per3 = new Person(); h.addObserver(per1);// 增加一个观察者 h.addObserver(per2);// 增加一个观察者 h.addObserver(per3);// 增加一个观察者 h.setPrice(6000.0f);// 要通知观察者内容已经被改变了 h.setName("wclxyn"); } } ~~~ ~~~ 2012-04-14 11:44:30.578----House.java----6000.0 2012-04-14 11:44:30.578----House.java----6000.0 2012-04-14 11:44:30.578----House.java----6000.0 2012-04-14 11:44:30.578----House.java----wclxyn 2012-04-14 11:44:30.578----House.java----wclxyn 2012-04-14 11:44:30.578----House.java----wclxyn ~~~ 这样具体的内容改变都会被监控了。 观察者模式在被观察者和观察者之间建立一个抽象的耦合,每一个具体的观察者都符合一个抽象观察者的接口,被观察者并不知道任何一个具体的观察者,他只知道他们有一个共同的接口,从而使得被观察者和观察者耦合度降低,而且观察者模式支持广播通信。被观察者会向所有注册过的观察者发出通知,但是如果一个被观察者有N个观察者那么在通知过程种会耗费大量的时间。
';

(十四)模板方法模式(Template)

最后更新于:2022-04-01 15:48:34

模板方法模式(Template)是行为模式之一,其就是简单定义一个算法执行骨架,而将其具体的算法延迟到子类中实现,从而使出现过多的类的时候不用再改变算法和结构直接添加一个实现子类就可以了。 一般在具体统一的操作步骤和业务功能,但是具有不同的细节处理,这样用模板方法模式减少了代码的复用。 下面简单的看看模板方法模式的原理图: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-07-12_57845609c007b.gif) 实例对象对于抽象类的继承,展开了具体的细节功能的处理,下面把模式应用到具体的实例: 简单的对于我们每天吃饭的情况(我旁边的各种情况),用一个普通的人作为吃饭的抽象类,然后定义吃早饭午饭晚饭都吃什么,通过不同的人对吃饭的要求也不一样对了一个小例子: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-07-12_57845609d2d04.gif) XHW分别是三种人,然后都有固定的一日三餐,但是吃的方式是不一样的: ~~~ package com.designpattern.template; public abstract class Person { public void eat() { breakfast(); lunch(); dinner(); } public abstract void breakfast(); public abstract void lunch(); public abstract void dinner(); } ~~~ 这里定义抽象类就是用来继承的,同时里面的eat是非抽象方法,这样子类可以不继承,直接实现父类指针指向子类,同时调用方法,但是对于早上中午晚上的方法,只必须要子类去继承的,所以就抽象了一下: ~~~ package com.designpattern.template; public class X extends Person { @Override public void breakfast() { System.out.println("早晨先吃两个麦面包片再喝一袋奶吃一个鸡蛋"); } @Override public void dinner() { System.out.println("中午去食堂三楼吃牛肉罩饼"); } @Override public void lunch() { System.out.println("晚上去食堂一楼吃饺子在来一碗盖饭"); } } ~~~ ~~~ package com.designpattern.template; public class W extends Person { @Override public void breakfast() { System.out.println("早晨没有时间吃早饭,于是就不吃了"); } @Override public void dinner() { System.out.println("中午去食堂二楼吃两个馒头一个菜一碗粥"); } @Override public void lunch() { System.out.println("晚上去食堂三楼吃一个饼一盘菜一碗粥"); } } ~~~ ~~~ package com.designpattern.template; public class W extends Person { @Override public void breakfast() { System.out.println("早晨没有时间吃早饭,于是就不吃了"); } @Override public void dinner() { System.out.println("中午去食堂二楼吃两个馒头一个菜一碗粥"); } @Override public void lunch() { System.out.println("晚上去食堂三楼吃一个饼一盘菜一碗粥"); } } ~~~ 然后在Client端调用: ~~~ package com.designpattern.template; public class Client { public static void main(String[] args) { System.out.println("H"); Person h = new H(); h.eat(); System.out.println(); System.out.println("W"); Person w = new W(); w.eat(); System.out.println(); System.out.println("X"); Person x = new X(); x.eat(); System.out.println(); } } ~~~ 输入内容如下 ~~~ H 早晨一般不吃饭,减肥 晚上去尚饮吃云吞什锦 中午在外面买一点煎饼什么的吃点 W 早晨没有时间吃早饭,于是就不吃了 晚上去食堂三楼吃一个饼一盘菜一碗粥 中午去食堂二楼吃两个馒头一个菜一碗粥 X 早晨先吃两个麦面包片再喝一袋奶吃一个鸡蛋 晚上去食堂一楼吃饺子在来一碗盖饭 中午去食堂三楼吃牛肉罩饼 ~~~ 这样就简单的实现了一个模板模式; 使用模板方法模式,在定义算法的骨架的同时,可以很灵活地实现具体的算法,满足用户灵活多变的需求。 虽然使用模板方法模式可以很自由滴实现具体的算法,但是如果算法的骨架有改变的话,则需要重新修改抽象类。
';

(十三)享元模式(Flyweight)

最后更新于:2022-04-01 15:48:32

享元模式(Flyweight)就是把部分和整体的关系用树形结构来表示,从而使客户端能够把一个个的部分对象和有他们组合起来的整体对象采用同样的方式看待,他也是一个继承的替代,其实具体的说,享元模式就是用时间交换了空间。用程序的运行速度来读取是否重复的对象内容,然后不创建一个重复的对象来节省空间,于此同时就大大提高了程序的运行效率。 下面就简单的原理图: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-07-12_57845609ab493.png) 然后通过一个字符的库创建简单的理解了一下享元模式,我们要创建一个字符库,这样就避免不了一些字符使我们想重复用的,这样如果我们每次用都重新的创建一个对象,然后分配空间,那么对于好多重复的字符会明显的浪费空间,这个时候就引入了享元模式。 首先创建一个字符的接口,定义了一个负责拿到所在实例中的字符的方法getName();如下: ~~~ package coml.designpattern.flyweight; public interface Characters { public String getName(); } ~~~ 紧接着定义了一个公用的子类实现了这个接口,书中是做了N个子类实现,这里我就用了一个子类,并在Flyweight种也有区别,个人觉得这样减少了代码的复用: ~~~ package coml.designpattern.flyweight; public class Character implements Characters { private String name; public Character(String name) { this.name = name; } @Override public String getName() { // TODO Auto-generated method stub return this.name; } } ~~~ 然后在Flyweight中定义创建字符的具体的方法和相关的逻辑: ~~~ package coml.designpattern.flyweight; import java.util.ArrayList; import java.util.List; public class Flyweight { private List list = new ArrayList(); public Characters getCharacter(String name) { Characters characters = null; for (int i = 0; i < list.size(); i++) { characters = (Characters) list.get(i); if (name.equals(characters.getName())) { System.out.println(name + "不是第一次使用,未分配空间"); break; } else { characters = null; } } if (characters == null) { characters = new Character(name); System.out.println(name + "第一次使用,并分配空间"); list.add(characters); } return characters; } } ~~~ 定义了一个list,每次有新对象的时候就放进去,然后每次调用GetCharacter时候都会去遍历整个list想要的对象有没有创建好,如果有就不再创建,如果没有在创建,书中这里是用了N个Characters的实现类,在if语句块里面定义了N中情况,每一个字符就是一个对象,我这里就一个实现类,然后用不同的引用而已, 其实效果是一样的,然后客户端的调用: ~~~ package coml.designpattern.flyweight; public class Client { public static void main(String[] args) { Flyweight flyweight = new Flyweight(); Characters study1 = flyweight.getCharacter("study"); Characters pattern = flyweight.getCharacter("pattern"); Characters study2 = flyweight.getCharacter("study"); Characters java = flyweight.getCharacter("java"); Characters study3 = flyweight.getCharacter("study"); Characters js = flyweight.getCharacter("js"); System.out.println(study1.getName() + "\t" + java.getName() + "\t" + study2.getName() + "\t" + pattern.getName() + "\t" + study3.getName() + "\t" + js.getName() + "\t"); } } ~~~ 输出结果: ~~~ study第一次使用,并分配空间 pattern第一次使用,并分配空间 study不是第一次使用,未分配空间 java第一次使用,并分配空间 study不是第一次使用,未分配空间 js第一次使用,并分配空间 study java study pattern study js ~~~ 这样发现study虽然使用了三次但是他只创建了一次,如果使用N次,那么会很明显的减少了空间的使用; 在数据库连接池就是实际中的应用,先创建好一个池,每次有人要取得数据不会再像JDBC一样创建一个新的连接,这样减少了服务器端的压力,提高了项目的性能; 使用享元模式可以大大节省空间,但是需要维护所有的享元对象,如果 要维护的享元很多,在查找的时候要消耗大量的时间,因此享元模式是典型的以时间来交换空间。
';

(十二)组合模式(Composite)

最后更新于:2022-04-01 15:48:30

树形结构在日常生活中是非常常见的,比如组织机构的这几,软件菜单的设计等,这些属性结构,他们的叶子节点和父节点在行为上基本是一致的。只是在父节点上可能又包含了子节点。这类应用在软件设计中,如果更好的来实现呢?这样我们就引出了下面对于组合模式的简单介绍: 组合模式(Composite)是整体与部分的关系,一个典型的应用就是树型结构,组合模式可以抽象出三种角色,分别为抽象构建角色(Component)、树枝构建角色(Composite)、树叶构建角色(Leaf). 抽象构件角色Component:它为组合中的对象声明接口,也可以为共有接口实现缺省行为。 树叶构件角色Leaf:在组合中表示叶节点对象——没有子节点,实现抽象构件角色声明的接口。 树枝构件角色Composite:在组合中表示分支节点对象——有子节点,实现抽象构件角色声明的接口;存储子部件。  下面简单的从原理图来理解这个组合模式: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-07-12_5784560995500.gif) 然后应用到了具体的实力,我简单的举例,比如现在我们的年级,在专业分流之前我们四个班级的,电气6、7、8、9班,然后通过一个Composite类对这四个班级的人数的统计,实例如下: 首先设计的是一个年级接口,定义了一个getCount方法获得这个年级所属班级的人数,从而达到一个一级一级节点的遍历,班级通过实现统一的接口,调用者对单一对象和组合对象的操作具有一致性。 ~~~ package com.designpattern.composite; public interface Grade { public int getCount(); } ~~~ 然后分别写了四个班级的代码: ~~~ package com.designpattern.composite; public class ElectricalClass6 implements Grade { @Override public int getCount() { return 53; } } ~~~ ~~~ package com.designpattern.composite; public class ElectricalClass7 implements Grade { @Override public int getCount() { return 68; } } ~~~ ~~~ package com.designpattern.composite; public class ElectricalClass8 implements Grade { @Override public int getCount() { return 70; } } ~~~ ~~~ package com.designpattern.composite; public class ElectricalClass9 implements Grade { @Override public int getCount() { return 69; } } ~~~ 紧接着写了一个Composite类,也实现这个年级的接口,同时实现年级Grade接口里面声明所有的用来管理子类对象的方法,以达到对年级Grade接口的最大化。目的就是为了使客户看来在接口层次上树叶和分支没有区别,达到一个对于实现的透明度。 ~~~ package com.designpattern.composite; import java.util.ArrayList; import java.util.List; public class Composite implements Grade { private List list = new ArrayList(); public Composite add(Grade grade) { list.add(grade); return this; } public Grade getChild(int i) { return (Grade) list.get(i); } @Override public int getCount() { int count = 0; for (int i = 0; i < list.size(); i++) { Grade grade = (Grade) list.get(i); count += grade.getCount(); } return count; } public Composite remove(Grade grade) { list.remove(grade); return this; } } ~~~ 同时这里的add和romove方法返回this指针,这样袭用的dom4j的设计思想,操作的时候可以反复的中这个方法返回对象继续进行想要的操作,同时在这里的Composite类和Class*类实现的是统一接口,这样实现了功能的一致性,调用起来更显得方便,如下: ~~~ composite.add(new ElectricalClass6()).add(new ElectricalClass7()); ~~~ 最后通过客户端的调用体现了组合方法的实用性: ~~~ package com.designpattern.composite; public class Client { public static void main(String[] args) { Composite grade = new Composite(); ElectricalClass6 class6 = new ElectricalClass6(); ElectricalClass7 class7 = new ElectricalClass7(); ElectricalClass8 class8 = new ElectricalClass8(); ElectricalClass9 class9 = new ElectricalClass9(); grade.add(class6).add(class7); System.out.println("电气6班和电气7班的人数:" + grade.getCount()); grade.add(class8); System.out.println("电气6班和电气7班和电气8班的人数:" + grade.getCount()); grade.remove(class6); System.out.println("电气7班和电气8班的人数:" + grade.getCount()); System.out.println("电气7班的人数:" + grade.getChild(0).getCount()); System.out.println("电气7班的人数:" + grade.remove(class8).getCount()); } } ~~~ 输出结构测试: ~~~ 电气6班和电气7班的人数:121 电气6班和电气7班和电气8班的人数:191 电气7班和电气8班的人数:138 电气7班的人数:68 电气7班的人数:68 ~~~ 使用组合模式能够提供比使用集成关系更灵活的功能,并且可以灵活的组合子对象和父对象之间的关系,从而使客户端的调用简单,客户端可以一致的使用组合结构或其中单个对象,用户就不比关系自己处理的是单个对象还是整个组合结构,这样大大的减少了客户端的代码。 同时组合模式使得向集合添加新类型的组建变得容易,只要这些组建提供一个相似的变成接口即可,但这也是他的缺点,因为这种做法很难限制某个类。
';

(十一)桥模式(birdge)

最后更新于:2022-04-01 15:48:28

简单的桥模式(birdge)将抽象与其实现解耦合,使他们的可以独立地变化,中文里把派生类叫做抽象的实现,而桥模式中所讲的实现恰恰不是这个意思,桥模式中的抽象类及派生类,实现指的是这些抽象类及派生类实现自己的方式。 简单的桥模式(birdge)的原理图 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-07-12_57845609804f5.png) 下面是关于这个模式的简单的一个例子程序,有一个鼠标抽象类,其这个鼠标分别属于联想和宏基生产的,这样用桥模式通过组合和继承,简单的实现了这种逻辑关系,并且达到了良好的复用,其实在实现的原理方面和上一个模--------装饰模式的实现原理是一样的: ~~~ package com.designpattern.bridge; public abstract class Mouse { private Computer computer; public Mouse(Computer computer) { this.computer = computer; } public void produce() { this.computer.produce(); } } ~~~ ~~~ package com.designpattern.bridge; public interface Computer { public void produce(); } ~~~ ~~~ package com.designpattern.bridge; public class BlackMouse extends Mouse { public BlackMouse(Computer computer) { super(computer); } @Override public void produce() { super.produce(); System.out.println("blackMouse"); } } ~~~ ~~~ package com.designpattern.bridge; public class RedMouse extends Mouse { public RedMouse(Computer computer) { super(computer); } @Override public void produce() { super.produce(); System.out.println("redMouse"); } } ~~~ ~~~ package com.designpattern.bridge; public class Lenovo implements Computer { @Override public void produce() { System.out.print("Lenovo's "); } } ~~~ ~~~ package com.designpattern.bridge; public class Acer implements Computer { @Override public void produce() { System.out.print("Acer's "); } } ~~~ ~~~ package com.designpattern.bridge; public class Client { public static void main(String[] args) { new BlackMouse(new Lenovo()).produce(); new RedMouse(new Lenovo()).produce(); new BlackMouse(new Acer()).produce(); new RedMouse(new Acer()).produce(); } } ~~~ 使用桥模式,能够提供比使用继承关系更灵活的功能,他可以使抽象和实现分离开,降低了耦合关系。当有新的抽象类或实现方式时,之需要集成一个抽象和继承一个实现即可。 如果如需重新抽象出另外的一个类型,则需要修改抽象。比如前面除了电脑品牌和鼠标之外,还可以把鼠标分为无线和有线,此时就需要重新抽象出一个类型来。
';

(十)装饰模式(Decorator)

最后更新于:2022-04-01 15:48:25

装饰模式(Decorator)就是使用被装饰的一个子类的实例,在客户端将这个子类的实例委托给装饰类。装饰模式是结成关系的一个替代方案。 简单的装饰模式是原理图入下: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-07-12_5784560950815.png) 装饰模式以对客服端透明的方式增添了对象的功能,其在与动态的给对象添加了责任,当然这里的继承便是静态的。 其中重要的地方时装饰对象和真是对象有相同的接口,这样客户端就可以和真是对象一样的交互方式和装饰对象交互,然后装饰对象把所有从客户端接收过来的请求全部转发给真是对象,然后在返还给客户端,这样装饰对象就可以再转发前或者以后添加一些附加功能而不影响对真是对象的操作,这样在不改变原有类的基础想,可以实现对于原有类的这种额外功能的实现,增强了程序的复用性。 同时装饰模式比继承好的地方就是,装饰模式可以动态的对已经存在的类进行任意的组合,实现想要的功能,而继承是静态的实现,不能改变原有类的实现,如果要添加更多的功能,只有添加更多的派生类来实现,这个简洁在下面的例子里对于最后一次打印输出就有很明显的效果,定义好了两个装饰类以后,不用再定义第三个就可以实现两个装饰类排列组合的效果。下面就简单的做了一个通过对于手机接电话的一个扩展,接听电话之前有一个彩铃,接受电话之后会回拨一段广告,这样就出来了下面的例子: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-07-12_5784560964774.png) ~~~ package com.designpattern.decorator; public interface Phone { public void recevieCall(String name); } ~~~ ~~~ package com.designpattern.decorator; public class ChinaMobile implements Phone { @Override public void recevieCall(String name) { System.out.println("step recevie " + name + " call"); } } ~~~ ~~~ package com.designpattern.decorator; public abstract class Decorator implements Phone { private Phone phone; public Decorator(Phone phone) { this.phone = phone; } @Override public void recevieCall(String name) { this.phone.recevieCall(name); } } ~~~ ~~~ package com.designpattern.decorator; public class RingBeforeChinaMobileDecorator extends Decorator { public RingBeforeChinaMobileDecorator(Phone phone) { super(phone); } @Override public void recevieCall(String name) { System.out.println("step ring before recevie " + name + "call"); super.recevieCall(name); } } ~~~ ~~~ package com.designpattern.decorator; public class AdAfterChinaMobileDecorator extends Decorator { public AdAfterChinaMobileDecorator(Phone phone) { super(phone); } @Override public void recevieCall(String name) { super.recevieCall(name); System.out.println("step ad after recevie " + name + " call"); } } ~~~ ~~~ package com.designpattern.decorator; public class Client { public static void main(String[] args) { Phone phone = new ChinaMobile(); Decorator decorator = new RingBeforeChinaMobileDecorator(phone); decorator.recevieCall("andimuise"); System.out .println("**************************"); decorator = new AdAfterChinaMobileDecorator(phone); decorator.recevieCall("halberd"); System.out .println("**************************"); decorator = new RingBeforeChinaMobileDecorator( new AdAfterChinaMobileDecorator(phone)); decorator.recevieCall("teacher"); System.out .println("**************************"); } } ~~~ 最终输出结果为,很明显在第三次输出的时候我想同时实现两种效果,就把另一个装饰类为为了其中一个装饰类的属性,因为无论是装饰类还是真实类他们是实现的共同的接口,这样就对实现提供了很好的效果 ~~~ step ring before recevie andimuisecall step recevie andimuise call ************************** step recevie halberd call step ad after recevie halberd call ************************** step ring before recevie teachercall step recevie teacher call step ad after recevie teacher call ************************** ~~~
';

(九)代理模式(Proxy)

最后更新于:2022-04-01 15:48:23

代理模式(Proxy)就是为其他对象提供一种代理以控制这个对象的访问,一个对象不想直接访问这个对象 具体Subject类:定义了RealSubject和Proxy的公用接口,这样就可以任何使用RealSubject的地方都可以用Proxy RealSubject类:定义了Proxy所代表的真实实体。 Proxy类:保存一个引用使得代理可以访问实体,并提供一个与Subject的接口相同的接口,这样代理就可以用来代替实体。 具体的代理模式的原理图: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-07-12_5784560929a6d.png) 简单的展示了一下对于Proxy的原理,然后今天自己琢磨了一下时序图也简单的做了一下,因为一直没有接触过,可能有好多错误呢: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-07-12_5784560939a59.png) 简单的叙述了一下,一个请求的提交过程,每次在调用一个类的方法的时候,都先经过这个类的代理(Proxy),下面就是一个简单的例子来笔记一下: ~~~ package com.designpattern.proxy; public interface Phone { public void show(); } ~~~ ~~~ package com.designpattern.proxy; public class IPhone4S implements Phone { private String owner; public IPhone4S(String owner) { this.owner = owner; } @Override public void show() { System.out.println("I'm " + owner + "'s IPhone4S which can do nothing while just a phone!"); } } ~~~ ~~~ package com.designpattern.proxy; public class Proxy implements Phone { private String owner; private IPhone4S phone; public Proxy(String owner) { this.owner = owner; } @Override public void show() { if (phone == null) { phone = new IPhone4S(owner); } phone.show(); } } ~~~ ~~~ package com.designpattern.proxy; public class Client { public static void main(String[] args) { Proxy proxy = new Proxy("halberd"); proxy.show(); } } ~~~ ~~~ I'm halberd's IPhone4S which can do nothing while just a phone! ~~~ 这样就简单的实现了代理模式,其实对于大多数结构型模式来说都一样,解决问题的思想是一样的,都是从添加中间件的方式达到一个解耦合的作用。 使用代理模式,能够在不改变原来代码工商的基础上对某一对象进行额外的控制,从而更好的体现对象中的单一职责。但是对于静态代理来说,一个接口只能服务于一种类型,如果要代理方法很多的时候,则要为每一个方法定义接口。这样就要学习一下动态代理和反射机制。今天被迫当了一天工人,好累啊,先睡了,明天找时间研究一下动态代理和反射机制,然后再补充到这里......
';

(八)适配器模式(Adapter)

最后更新于:2022-04-01 15:48:21

适配器模式(Adapter)就是由源到目标的一个适配,通常我们定义的接口或者类里面提供了好多方法,但是定义好的接口里面的方法有时候用起来不是很符合我们的需要,这时候如果去修改源码也不是一个好方法,通常设计的时候也很少修改源码的。这样就提供了适配器这个类,用一个类来达到源和目标的匹配就可以了,当然可以实现我们想要的各种匹配。 在Spring,IO里面都有这方面的设计,最简单的BeanUtils里面的转换器就是一个很好的应用,就是当我们使用BeanUtils的时候,它一般只支持8种基本数据类型,简单的写一个例子,如果我们的VO里面的属性都是基础类型的这样就能操作了: ~~~ package com.hiccer.cms.utils; import java.lang.reflect.InvocationTargetException; import java.util.Iterator; import java.util.Map; import java.util.Set; import javax.servlet.http.HttpServletRequest; import org.apache.commons.beanutils.BeanUtils; public class RequestUtils { public static Object copyParams(Class entryClass, HttpServletRequest request) { try { Object entity = entryClass.newInstance(); Map allParams = request.getParameterMap(); Set entries = allParams.entrySet(); for (Iterator iterator = entries.iterator(); iterator.hasNext();) { Map.Entry entry = (Map.Entry) iterator.next(); String name = (String) entry.getKey(); String[] value = (String[]) entry.getValue(); if (value != null) { if (value.length == 1) { BeanUtils.copyProperty(entity, name, value[0]); } else { BeanUtils.copyProperty(entity, name, value); } } } return entity; } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } return null; } } ~~~ 这时候如果我们想要让BeanUtils也能操作我们自己定义的VO对象里面的类型,我这里是有一个Channel对象作为Article对象的属性,就要定义如下:Converter来实现这个功能,这就是一个简单的适配器编程方式: ~~~ package com.hiccer.cms.utils; import java.util.HashSet; import java.util.Set; import org.apache.commons.beanutils.Converter; import com.hiccer.cms.backend.vo.Channel; public class ChannelsConverter implements Converter { @Override public Object convert(Class type, Object value) { String[] channelIds = null; if (value instanceof String) { channelIds = new String[] { (String) value }; } if (value instanceof String[]) { channelIds = (String[]) value; } if (channelIds != null) { Set channels = new HashSet(); for (String channelId : channelIds) { Channel c = new Channel(); c.setId(Integer.parseInt(channelId)); channels.add(c); } return channels; } return null; } } ~~~ 那么我们这样写一个 适配器模式(Adapter)的简单的原理图: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-07-12_5784560916c6d.png) 这次我把UML类图也添加了备注,把图片放大了,这样方便查看和复习,同时清楚了实线空心箭头是“继承的”的意思,虚线空心箭头是“实现了”的意思,上面用的是去实现了,其实有的版本上面确切是是用实线箭头,就是关联的意思,其实表达出大致的意思就行了。 适配器模式有两种,一种是类适配器,一种是对象适配器,其宗旨都是解决源对于目标的不匹配,下面分别从简单的例子看两种适配器然后整体分析: 第一种适配器 我的电脑耳机坏了,但是我耳机是USB2.0的插口,不幸运的是我只有一个3.0的耳机了,于是我去买了一个适配器把3.0的和2.0的接到了一起,就能用了,事例代码如下: ~~~ package com.designpattern.adapter; public interface USB2 { public void need(); } ~~~ ~~~ package com.designpattern.adapter; public class USB3 { public void add() { System.out.println("I'm a USB3.0 headset"); } } ~~~ ~~~ package com.designpattern.adapter; public class Adapter extends USB3 implements USB2 { @Override public void need() { this.add(); } } ~~~ ~~~ package com.designpattern.adapter; public class Client { public static void main(String[] args) { Adapter adapter = new Adapter(); adapter.add(); } } ~~~ 这样就直接打印了: ~~~ I'm a USB3.0 headset ~~~ 这样Adapter继承了USB3这个类,java中的单继承不允许它在继承别的类了,所以就不能再实现别的目标类的需求了,所以这样就叫做类适配器,量身为一个类做的一个适配器。其实这种类的适配模式用于单一源的适配,由于它的源的单一话,代码实现不用写选择逻辑,很清晰;而对象的适配模式则可用于多源的适配,弥补了类适配模式的不足,使得原本用类适配模式需要写很多适配器的情况不复存在,弱点是,由于源的数目可以较多,所以具体的实现条件选择分支比较多,不太清晰。同时在对象的适配器里面,通常是把源或者是目标聚合到适配器里面,就是和适配器拥有共同的生命周期,放在适配器的构造器里面,个人觉得在源放在放在适配器里面比较好,可能多数的时候是在适配器面接收目标的要求,然后通过对要求的分析,解析在用源的实例去调用源的方法的。 下面就简单的写了一个对象的适配器的例子: 我定义了一个类Utils简单的用List存放了三个字符串,作为我的源,但是我的Application用的时候是必须是HashMap,这样我就不能用了,于是定义的一个ListAdapter类,来解决这两个问题,具体代码如下: ~~~ package com.designpattern.adapter; import java.util.ArrayList; import java.util.List; public class Utils { @SuppressWarnings("unchecked") public static List getElements() { List list = new ArrayList(); list.add("first"); list.add("second"); list.add("third"); return list; } } ~~~ ~~~ package com.designpattern.adapter; import java.util.HashMap; public class Application { @SuppressWarnings("unchecked") public static void print(HashMap map) { for (int i = 0; i < map.size(); i++) { System.out.print(map.get(i) + " "); } } } ~~~ ~~~ package com.designpattern.adapter; import java.util.HashMap; import java.util.List; @SuppressWarnings( { "unchecked", "serial" }) public class ListAdapter extends HashMap { @SuppressWarnings("unchecked") private List list; @SuppressWarnings("unchecked") public ListAdapter(List list) { this.list = list; } public int size() { return list.size(); } public Object get(Object i) { return list.get((Integer.valueOf(i.toString())).intValue()); } } ~~~ ~~~ package com.designpattern.adapter; public class Client { public static void main(String[] args) { System.out.println(Utils.getElements()); ListAdapter listadapter = new ListAdapter(Utils.getElements()); Application.print(listadapter); } } ~~~ 这样就自然的打印处理如下内容: ~~~ [first, second, third] first second third ~~~ 其旨在对于仅能操作HashMap的用户一样可以使用这个只能操作List的工具包。 使用适配器模式,可以讲一个系统的接口和本来不相容的另一个系统的类联系起来,从而使得这两个类能够一起工作,强调了对接口的转换。 这里也简单的说一下默认适配器模式: 这个么模式是大多数API接口使用的方式,以方便用户的使用,简单的定义一个接口里面有好多方法,为了不不得不的实现那么多方法,紧接着定义一个抽象类来实现这个接口,这样就可以继承抽象类来重写自己想要的方法而不写过多的没有意义的方法了。简单的例子如下: ~~~ package com.designpattern.adapter; public interface Phone { public void sendMessage(); public void surfInternet(); public void receiveCall(); public void AsAlarm(); } ~~~ ~~~ package com.designpattern.adapter; public abstract class ChinaMobile implements Phone { @Override public void AsAlarm() { // TODO Auto-generated method stub } @Override public void receiveCall() { // TODO Auto-generated method stub } @Override public void sendMessage() { // TODO Auto-generated method stub } @Override public void surfInternet() { // TODO Auto-generated method stub } } ~~~ ~~~ package com.designpattern.adapter; public class MyPhone extends ChinaMobile { @Override public void AsAlarm() { System.out.println("I just use it as a alarm!"); } } ~~~
';

(七)外观模式(Facade)

最后更新于:2022-04-01 15:48:18

外观模式(Facade)为了小小的纠正一下个人的口语,于是有道了一下:[fə'sɑ:d] 对于外观模式就是为了子系统对外提供的一组接口提供一个统一的界面,似的其他系统对该系统访问都通过一个同一段的界面来完成。 外观模式主要由三部分组成,一个中间类,就是Facade类,负责联系子系统提供对外的接口,一个是多个子系统,一个是客户端负责通过Facade类对子系统的功能进行操作。 这里通过简单的工厂生产帽子,被子,笔卖给消费者的过程,并且用Facade类的前后作对比来简单的理解Facade模式: Facade模式的原理图: 对UML部分理解更清楚了一点,发现前面的UML好多不合理的地方,可以学习 [http://blog.csdn.net/zhengzhb/article/details/7187278](http://blog.csdn.net/zhengzhb/article/details/7187278) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-07-12_578455cd02cab.png) 普通基础的设计: ~~~ package com.designpattern.facade; public class HatFactory { public static void saleHat() { System.out.println("sale a hat"); } } ~~~ ~~~ package com.designpattern.facade; public class CapFactory { public static void saleCap() { System.out.println("sale a cap"); } } ~~~ ~~~ package com.designpattern.facade; public class PenFactory { public static void salePen() { System.out.println("sale a pen"); } } ~~~ ~~~ package com.designpattern.facade; public class Client { public static void main(String[] args) { CapFactory.saleCap(); HatFactory.saleHat(); PenFactory.salePen(); } } ~~~ 这样如果客户想买各种商品的话就必须直接和厂家联系,然后买商品,实现起来却是很是麻烦,但是如果引入了如下的Facade类就简单多了,具体操作如下: ~~~ package com.designpattern.facade; public class Facade { public static void saleHat() { HatFactory.saleHat(); } public static void saleCap() { CapFactory.saleCap(); } public static void salePen() { PenFactory.salePen(); } } ~~~ ~~~ package com.designpattern.facade; public class Client { public static void main(String[] args) { Facade.saleCap(); Facade.saleHat(); Facade.salePen(); } } ~~~ 这样在客户买商品的时候只要去Facade商店就行了,直接到商店想买什么就买什么,具体商店和厂家怎么联络的客户是不用去理会的,这样就对于客户端程序员提供了很大的简便可行。一些很好的持久层的框架也是用这样一个设计模式达到一个很好的用户体验。 外观模式通过提供一个统一的对外接口,避免的外部系统和子系统之间的直接联系从而降低了系统间的依赖和复杂度。 但是限制了外部系统对子系统调用的灵活性,只能按照外观类中提供的方式对子系统进行调用。
';

(六)单例模式(Singleton)

最后更新于:2022-04-01 15:48:16

单例模式就是确保一个类只有一个实例,并且该实例必须自动创建,并向整个系统提供该实例。这样保证了对外的对象的属性等均为一个实例,就像是银行取款 单例模式原理图: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-07-12_578455cce0a88.png) 单例模式分为饿汉式单例模式和懒汉式单例模式。 饿汉式单例模式代码 ~~~ package com.designpattern.singleton; public class HungrySingleton { private HungrySingleton() { } private static HungrySingleton instance = new HungrySingleton(); public static HungrySingleton getInstance() { return instance; } } ~~~ 懒汉式单例模式代码 ~~~ package com.designpattern.singleton; public class LazySingleton { private LazySingleton() { } private static LazySingleton instance = null; public static synchronized LazySingleton getInstance() { if (instance == null) { instance = new LazySingleton(); } return instance; } } ~~~ 事例中对于饿汉式是不管外部有没有调用都new出了一个对象,二懒汉式只有在外部调用的时候,并且是第一次的时候才new出来对象的,但是一定要放在sychronized下面 这样感觉像是懒汉模式是在调用的时候分配空间初始化instance的,但是自己感觉上面两种是一样的效果 在实例化先后顺寻的角度分析:饿汉式类内static 对象会在构造器调用前初始化,也就是最先初始化,但是只初始化一次就不再初始化了,毕竟是static的,在构造器之前也就是只有在使用这个类的时候,才实例化。同时后者懒汉式中私有的static也会在构造器之前初始化,但是是null,这样就在第一次调用这个类的时候对instance进行了初始化,但是之后就不会再初始化了,原因也是static,这样看起来对于懒汉和饿汉的初始化和构造过程是一样的。 不过说道具体的地方饿汉式是在加载类的时候创建对象,而懒汉式是在调用getInstance时候创建对象,那么这样他们在创建的时候还是用一定的区别的。 下面借着这个Singleton模式简单的做了一个Log工具,实现对于一个日志工具不会多次初始化,并且不会覆盖掉而是尾加,Log4j就是一个Singleton的实例 ~~~ package com.designpattern.singleton; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.text.SimpleDateFormat; import java.util.Date; public class Log { private static final String DefalutLogFilePathName = System .getProperty("user.dir") + File.separator + "user.log"; private static Log log; private static PrintWriter pw; private Log() { pwinit(); } public static synchronized void log(String message) { if (log == null || pw == null) { log = new Log(); } if (pw != null) { pw.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss") .format(new Date()) + " : " + message); } } public static void destroy() { log = null; if (pw != null) { pw.close(); } } private void pwinit() { if (pw == null) { try { pw = new PrintWriter(new FileWriter(DefalutLogFilePathName, true), true); } catch (IOException e) { e.printStackTrace(); pw = null; } } } } ~~~ 在Client端对Log进行操作,不会覆盖结果,测试成功 ~~~ package com.designpattern.singleton; public class Client { public static void main(String[] args) { System.out.print("Log"); System.out.print("\t"); Log.log("start"); Log.log("middle"); Log.log("end"); Log.destroy(); } } ~~~ 输出结果: ~~~ 2012-04-05 14:46:15 : start 2012-04-05 14:46:15 : middle 2012-04-05 14:46:15 : end ~~~ 在单例模式中,客户调用类的实例时,只能调用一个公共接口,这就是为整个开发团队提供了共享的概念。 但是但是模式的类在实例化以后,不能被别的类继承,在分布式系统中,当系统中的单例类被复制运行在多个虚拟机下时,在每一个虚拟机下都会创建一个实例对象,此时如果想知道具体那个虚拟机下运行着哪个单例对象是很困难的,而且单例类很难实现序列化。
';

(五)原型模式(Prototype)

最后更新于:2022-04-01 15:48:14

原型模式就是通过一个原型对象来表明要创建的对象类型,然后用复制这个原型对象的方法来创建更多同类型的对象。 自己对原型模式简单理解的原理图如下: 具体属性没有添加: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-07-12_578455ccc8ed4.png) 原型模式里面关键点就在一个Cloneable接口和clone方法的重写 下面就通过一个配钥匙的例子简单的写了一个程序,起初一个一个抽象类,这样可以重写clone方法,如果是接口的话就得到子类里面把重写的方法具体声明,这样的话对于程序的复用性不是很好,于是就写了一个抽象的类KeyPrototype然后,写了两个子类继承一个客户端,代码如下: ~~~ package com.designpattern.prototype; public abstract class KeyPrototype implements Cloneable { private String color; private float length; private float thick; @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } @Override public String toString() { return this.getClass() + " -> Color:" + this.getColor() + " Length:" + this.getLength() + " Thick:" + this.getThick(); } public String getColor() { return color; } public float getLength() { return length; } public float getThick() { return thick; } public void setColor(String color) { this.color = color; } public void setLength(float length) { this.length = length; } public void setThick(float thick) { this.thick = thick; } } ~~~ ~~~ package com.designpattern.prototype; public class CopperKey extends KeyPrototype { } ~~~ ~~~ package com.designpattern.prototype; public class AluminiumKey extends KeyPrototype { } ~~~ ~~~ package com.designpattern.prototype; public class Client { public static void main(String[] args) { KeyPrototype copperkey = new CopperKey(); copperkey.setColor("red"); copperkey.setLength(12); copperkey.setThick(2); System.out.println(copperkey); try { KeyPrototype aluminaumkey = (KeyPrototype) copperkey.clone(); aluminaumkey.setColor("yellow"); aluminaumkey.setLength(10); aluminaumkey.setThick(5); System.out.println(aluminaumkey); } catch (CloneNotSupportedException e) { e.printStackTrace(); } } } ~~~ ~~~ class com.designpattern.prototype.CopperKey -> Color:red Length:12.0 Thick:2.0 class com.designpattern.prototype.CopperKey -> Color:yellow Length:10.0 Thick:5.0 ~~~ 这样就简单对前者进行的复制,很显然他们并不是一个对象,里面关于clone的东西做了一个简单的总结 同时来证明他们确实是两个对象,就是改动里面的属性不互相影响: 首先我创建了一个Dog类 ~~~ package com.note.clone; public class Dog/* implements Cloneable */{ private String color; private String name; public Dog(String name,String color){ this.name = name; this.color = color; } public String getColor() { return color; } public void setColor(String color) { this.color = color; } public String getName() { return name; } public void setName(String name) { this.name = name; } /* @Override protected Object clone() throws CloneNotSupportedException { // TODO Auto-generated method stub return super.clone(); }*/ @Override public String toString() { return this.getClass()+" "+this.getName()+" "+this.getColor(); } } ~~~ 然后写了一个Tom类,其中Tom类里面有私有属性Dog ~~~ package com.note.clone; public class Tom implements Cloneable { private String color; private Dog dog = new Dog("mimi", "yellow");; private String name; @Override protected Object clone() throws CloneNotSupportedException { Tom o = null; o = (Tom)super.clone(); // o.setDog((Dog)o.getDog().clone()); return o; } public String getColor() { return color; } public Dog getDog() { return dog; } public String getName() { return name; } public void setColor(String color) { this.color = color; } public void setDog(Dog dog) { this.dog = dog; } public void setName(String name) { this.name = name; } @Override public String toString() { return this.getClass() + " " + this.getName() + " " + this.getColor() + "\n" + "Dog:" + this.dog; } } ~~~ 然后写了一个People类简单的对上述的两个程序进行测试: ~~~ package com.note.clone; public class People { public static void main(String[] args) { Tom tom = new Tom(); tom.setName("Tom"); tom.setColor("blue"); System.out.println(tom); System.out.println(); try { Tom tylo = (Tom) tom.clone(); tylo.setName("tylo"); tylo.setColor("red"); tylo.getDog().setName("lucky"); tylo.getDog().setColor("green"); System.out.println(tylo); System.out.println(); System.out.println(tom); System.out.println(); Dog dog = tylo.getDog(); dog.setName("hello"); dog.setColor("white"); System.out.println(tylo); System.out.println(); System.out.println(tom); System.out.println(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } } } ~~~ 运行结果如下: ~~~ class com.note.clone.Tom Tom blue Dog:class com.note.clone.Dog mimi yellow class com.note.clone.Tom tylo red Dog:class com.note.clone.Dog lucky green class com.note.clone.Tom Tom blue Dog:class com.note.clone.Dog lucky green class com.note.clone.Tom tylo red Dog:class com.note.clone.Dog hello white class com.note.clone.Tom Tom blue Dog:class com.note.clone.Dog hello white ~~~ 这样很明确的表明了对于这两个对象的属性,自己的属性除了Dog以外都是自己的,没有对着对方的属性的改变而改变,但是Dog属性,两个对象的属性是一样的 那么这里就到了深度克隆 我们把Dog和Tom里注释掉的内容打开再运行People程序,运行结果如下: ~~~ class com.note.clone.Tom Tom blue Dog:class com.note.clone.Dog mimi yellow class com.note.clone.Tom tylo red Dog:class com.note.clone.Dog lucky green class com.note.clone.Tom Tom blue Dog:class com.note.clone.Dog mimi yellow class com.note.clone.Tom tylo red Dog:class com.note.clone.Dog hello white class com.note.clone.Tom Tom blue Dog:class com.note.clone.Dog mimi yellow ~~~ 很明显发现,两个对象的Dog属性也没有互相影响,说明了他们不是用的一个引用,这样也证明了上面的例子,他们分别是一个对象,达到了克隆复用的应用。 在原型模式中,可以动态的添加产品分类,而且对整体结构没有影响。 由于原型模式需要给每一个类都配备一个克隆方法,这就需要在这几类的时候通盘考虑,因为在已有类的基础上来添加clone操作时比较困难的,而且原型模式在实现深层的复制时,需要编写一定量的代码。
';

(四)创建者模式(Builder)

最后更新于:2022-04-01 15:48:12

创建者模式主要是为了所谓的高聚合,解耦合,遇到多种配件于一身的情况的时候,放在实体类里面不合适,放在工厂类也不合适,所以就添加了一个创建者类,专门对相应的零件进行组装,如同汽车了N中配件,同时要是各种配件互相联系的话也在这个Builder里面一并做了。 明天准备去爬山,这个原理图就再补上吧: 今天把uml补上了,不过对于uml初学的我就乱乱的先随便画一个吧,等以后慢慢入门了在斟酌里面的错误和细节: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-07-12_578455ccaf4da.png) 下面是我自己攒出来的例子(回来的时候着急,把书忘教室了,不知道书上怎么写的,不过明显记得一处错误,构造器也加上了一个void),为了在Builder里面优化一下,用了一下反射,这样就可以直接通过多态来实现对于派生类中的实体类进行初始化并且操作了,简单的实现电脑的组装:通过工厂类实例化Computer的父类指向子类的实例,然后在Builder里面添加一个工厂类的私有变量,通过构造器把要穿件的Computer实例传入Builder,然后对其进行解析,反射得到路径,对其派生类里面的方法进行反射得到相应的配件的集成,转配完成。少说多做: ~~~ package com.designpattern.builder; public interface Mouse { public void add(); } ~~~ ~~~ package com.designpattern.builder; public interface Monitor { public void add(); } ~~~ ~~~ package com.designpattern.builder; public interface Keyboard { public void add(); } ~~~ ~~~ package com.designpattern.builder; public interface Displayer { public void add(); } ~~~ ~~~ package com.designpattern.builder; public interface Factory { public Computer buildComputer(); } ~~~ ~~~ package com.designpattern.builder; public interface Computer { public void add(); } ~~~ ~~~ package com.designpattern.builder; public class AcerMouse implements Mouse { @Override public void add() { System.out.println("add AcerMouse"); } } ~~~ ~~~ package com.designpattern.builder; public class AcerMonitor implements Monitor { @Override public void add() { System.out.println("add AcerMonitor"); } } ~~~ ~~~ package com.designpattern.builder; public class AcerKeyboard implements Keyboard { @Override public void add() { System.out.println("add AcerKeyboard"); } } ~~~ ~~~ package com.designpattern.builder; public class AcerDisplayer implements Displayer { @Override public void add() { System.out.println("add AcerDisplayer"); } } ~~~ ~~~ package com.designpattern.builder; public class AcerFactory implements Factory { @Override public Computer buildComputer() { return new Acer(); } } ~~~ ~~~ package com.designpattern.builder; public class Acer implements Computer { @Override public void add() { System.out.println("builder Acer"); } } ~~~ ~~~ package com.designpattern.builder; import java.lang.reflect.Method; public class Builder { private Factory factory; public Builder(Factory factory) { this.factory = factory; } public void builder() throws Exception { factory.buildComputer().add(); String computer = factory.getClass().toString(); computer = computer.substring(6, computer.length() - 7); // build Mouse Class c = Class.forName(computer + "Mouse"); Mouse mouse = (Mouse) c.newInstance(); Method method = c.getMethod("add", null); method.invoke(mouse, null); // build Keyboard c = Class.forName(computer + "Keyboard"); Keyboard keyboard = (Keyboard) c.newInstance(); method = c.getMethod("add", null); method.invoke(keyboard, null); // build Displayer c = Class.forName(computer + "Displayer"); Displayer displayer = (Displayer) c.newInstance(); method = c.getMethod("add", null); method.invoke(displayer, null); // build Monitor c = Class.forName(computer + "Monitor"); Monitor monitor = (Monitor) c.newInstance(); method = c.getMethod("add", null); method.invoke(monitor, null); System.out.println("build complete"); } } ~~~ ~~~ package com.designpattern.builder; public class Client { public static void main(String[] args) { try { new Builder(new AcerFactory()).builder(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } } ~~~
';

(三)抽象工厂模式(AbstractFactory)

最后更新于:2022-04-01 15:48:09

抽象工厂模式(AbstractFactory)原理图 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-07-12_578455cc9c83d.png) 初学uml不会排版,就这样凑合吧,展现大概就行了 抽象,果然挺让我理解的抽象的,其实一个挺简单的模式,但是这样乱乱的画出来其实就是通过工厂创建出对象而已,只不过是对于工厂的分类方式和对于产品的分类方式不一样了而已,上面是最合理的方式(起码这个书上我是这么理解的),其实我自己觉得可以有别的方法 比如我不是按照产品的种类分类,按照产品的级别分类,就是简单的把Product、AProductB替代1和2,这样也可以的,就是用下面的代码来说,非洲的狮子和美洲的狮子,都是狮子,但是非洲的狮子和非洲的海豚都是非洲的动物,一样可以说的同,这样就有多了一种方式去表达同一个模式,就像是上面的原理图到了工厂这里就编程了通过商品实例化不同的级别,就像是下面的代码,用非洲来实例化非洲的动物,这本身就是一种互相交互的东西,如果说把一类产品放到一起将来添加模块的时候好添加,那么如果我想增加的是种类,或者是个别,那么总会有不好重构的一个地方的,不过对于一个对象的抽象,还是按照上面的抽象出来的实力比较具体一些而已,同时只要是抽象的工厂和抽象的对象不是按照一个区别来分的,就完全可以达到效果,我看了一些网上的设计模式的解析大部分也是按照上面的图例做的,我觉得应该可以按照多种方式去考虑吧,只是不同人有不同的思路而已,大概是对于类的分类和继承没有像我这样钻缝子的。好吧,简单的做一下笔记开始下一个模式,等长大一点了在慢慢钻这个缝子(个人理解): ~~~ package com.designpattern.abstractfactory; public interface Animal { public void eat(); } ~~~ ~~~ package com.designpattern.abstractfactory; public class Dolphin implements Animal { @Override public void eat() { System.out.println("Dolphin is eating"); } public void swim(){ System.out.println("Dolphin is swimming"); } } ~~~ ~~~ package com.designpattern.abstractfactory; public class AfricaDolphin extends Dolphin { public void eat(){ System.out.println("AfricaDolphin is eating"); } public void swim(){ System.out.println("AfricaDolphin is swimming"); } } ~~~ ~~~ package com.designpattern.abstractfactory; public class AsiaDolphin extends Dolphin { public void eat(){ System.out.println("AsiaDolphin is eating"); } public void swim(){ System.out.println("AsiaDolphin is swimming"); } } ~~~ ~~~ package com.designpattern.abstractfactory; public class Tiger implements Animal { @Override public void eat() { System.out.println("Tiger is eating"); } public void run(){ System.out.println("Tiger is running"); } } ~~~ ~~~ package com.designpattern.abstractfactory; public class AfricaTiger extends Tiger { public void eat(){ System.out.println("AfricaTiger is eating"); } public void run(){ System.out.println("AfricaTiger is running"); } } ~~~ ~~~ package com.designpattern.abstractfactory; public class AsiaTiger extends Tiger { public void eat(){ System.out.println("AsiaTiger is eating"); } public void run(){ System.out.println("AsiaTiger is running"); } } ~~~ ~~~ package com.designpattern.abstractfactory; public interface Factory { public Animal createTiger(); public Animal createDolphin(); } ~~~ ~~~ package com.designpattern.abstractfactory; public class AsiaFactory implements Factory { @Override public Animal createDolphin() { // TODO Auto-generated method stub return new AsiaDolphin(); } @Override public Animal createTiger() { // TODO Auto-generated method stub return new AsiaTiger(); } } ~~~ ~~~ package com.designpattern.abstractfactory; public class AfricaFactory implements Factory { @Override public Animal createDolphin() { // TODO Auto-generated method stub return new AfricaDolphin(); } @Override public Animal createTiger() { // TODO Auto-generated method stub return new AfricaTiger(); } } ~~~ ~~~ package com.designpattern.abstractfactory; public class Client { public static void main(String[] args) { Factory factory = new AfricaFactory(); Animal tiger = factory.createTiger(); tiger.eat(); Animal dolphin = factory.createDolphin(); dolphin.eat(); factory = new AsiaFactory(); tiger = factory.createTiger(); tiger.eat(); dolphin = factory.createDolphin(); dolphin.eat(); } } ~~~ 在抽象工厂模式中,客户端不在负责对象的创建,而是把这个责任交给了具体的工厂类,客户端只负责对对象的调用,从而明确各个类的职责。 当一些类的互相关联的产品被设计到一个工厂类里后,客户端的调用将会变得非常简单,而且如果要更换这一系列的产品,只需要跟换一个工厂类即可。 但是如果新的产品添加进来,则需要修改抽象工厂类的设计,同时修改实现这个抽象工厂类的具体的实现,需要额外添加代码。
';

(二)工厂方法模式(FactoryMethod)

最后更新于:2022-04-01 15:48:07

工厂方法模式原理图: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-07-12_578455cc845ca.png) 具体实现代码: ~~~ package com.designpattern.factorymethod; public interface FactoryMethod { public Animal createAnimal(); } ~~~ ~~~ package com.designpattern.factorymethod; public class DolphinFactory implements FactoryMethod { @Override public Animal createAnimal() { return new Dolphin(); } } ~~~ ~~~ package com.designpattern.factorymethod; public class TigerFactory implements FactoryMethod { @Override public Animal createAnimal() { return new Tiger(); } } ~~~ ~~~ package com.designpattern.factorymethod; public interface Animal { public void eat(); } ~~~ ~~~ package com.designpattern.factorymethod; public class Dolphin implements Animal { @Override public void eat() { System.out.println("Dolphin is eating"); } public void swim() { System.out.println("Dolphin is swimming"); } } ~~~ ~~~ package com.designpattern.factorymethod; public class Tiger implements Animal { @Override public void eat() { System.out.println("Tiger is eating"); } public void run() { System.out.println("Tiger is running"); } } ~~~ ~~~ package com.designpattern.factorymethod; public class Client { public static void main(String[] args) { FactoryMethod factory = new TigerFactory(); Animal tiger = factory.createAnimal(); tiger.eat(); factory = new DolphinFactory(); Animal dolphin = factory.createAnimal(); dolphin.eat(); } } ~~~ 在工厂方法模式中,客户端不在负责对象的创建,而是把这个责任交给了具体的工厂类,客户端只负责对象的调用,从而明确各个类的职责。 如果有新的产品加进来,只需要新增加一个具体的创建产品的工厂类和具体的产品类就可以了,不会影响但原来的其他的代码,代码量也不会变大,后期维护更加容易,增强了系统的可扩展性。 但是使用这个模式的时候而外地编写代码,增加了工作量。
';

(一)简单工厂模式(SimpleFatory)

最后更新于:2022-04-01 15:48:05

一点点从基础做起,23中设计模式一天看一个 首先学习了一个UML,但是没有能下到RationalRose,想去官网上下载,但是似乎收费,索性就用手头上的StartUML,其实就是一个工具,能实现就行了 SimpleFactory——简单设计模式原理图 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-07-12_578455cc584f8.png) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-07-12_578455cc6da29.png) ~~~ package com.designpattern.simplefactory; public class Client { public static void main(String[] args) { Animal tiger = SimpleFactory.createAnimal("Tiger"); tiger.eat(); Animal dolphin = SimpleFactory.createAnimal("Dolphin"); dolphin.eat(); } } ~~~ ~~~ package com.designpattern.simplefactory; public class SimpleFactory { public static Animal createAnimal(String animalName) { if ("Tiger".equals(animalName)) { return new Tiger(); } else if ("Dolphin".equals(animalName)) { return new Dolphin(); } return null; } } ~~~ ~~~ package com.designpattern.simplefactory; public interface Animal { public void eat(); } ~~~ ~~~ package com.designpattern.simplefactory; public class Dolphin implements Animal { @Override public void eat() { System.out.println("Dolphin is eating"); } public void swim() { System.out.println("Dolphin is swimming"); } } ~~~ ~~~ package com.designpattern.simplefactory; public class Tiger implements Animal { @Override public void eat() { System.out.println("Tiger is eating"); } public void run() { System.out.println("Tiger is running"); } } ~~~ 简单工厂设计模式中,客户端不在负责对象的创建,而是把这个任务丢给了具体的工厂类,客户端置负责对对象的简单的调用,从而明确了各个类的职责。 由于简单的工厂模式使用静态的方法来创建对象,这就导致了静态方法无法被继承。另一方面,这个工厂类负责所有对象的创建,这回导致虽然具体的产品的不断增多,可能客户端对于某些产品的创建方式会有不同的要求,这样的话,就要不断的修改工厂类,增加了相应的判断逻辑,不利于后期的维护。 其实从这个简单的工厂模式的原理可以看出,原来在客户端要做的创建和初始化工作都被移到了工厂里去做,这样做,虽然是把创建对象和初始化工作于客户端分离了,实现了这部分的责任分配,但所有对象创建和初始化的工作还是都集中在了这个具体的工厂类里面,这样如果要创建的对象很多,这个工厂将会非常庞大,仍然不利于后期代码的维护。因此简单工厂模式只是使用与要创建的对象比较少和简单的时候,因此这个设计模式看一下过去就行了,也没有必要再这个上面下多大功夫,毕竟还是比较简单的东西,如果多了怎么办呢,这样就到了期待的下一个设计模式Factory Method
';

前言(目录、源码、资料)

最后更新于:2022-04-01 15:48:03

这两天就结了好几天,其实原因太没趣了,就是不知道自己的学习方向了 不过也没有那么麻烦就是不知道手头的四本书的阅读顺序,觉得哪个都挺重要的,但是一起看吧,时间怎么安排,不一起看吧,又都放不下,不过说回来真不是什么大事,就是想具体简单的规划一下自己的学习进程,不然心里乱乱的 《易学设计模式》《java编程细想》《Apache Tomcat高级编程》《linux鸟哥的私房菜》 于是就做了简单的安排 说回来都是动手能力比较强的书籍,就像原来我海量看视频的时候,不动手敲是很难提高的,但是我还是分了一个主次 放学回家的时候就看《Apache Tomcat高级编程》一遍看一遍配置,主要是tomcat分析和apache,iis等一下集成的操作和原来,这样能动起手来更快一些 在学校的时候: 如果在中心(实验室),就看《linux鸟哥的私房菜》,一边看一边操作,这样也是可以的 如果在教室就看《易学设计模式》《java编程细想》,每天坚持看一个设计模式,然后就看《java编程细想》,不过看完了就把好的地方记下来,回去上机操作 这样的话虽然有点乱,好像一个人不能兼顾好多一样,但是说回来,可以让我哪个东西都不落下,不然等我就看一个《java编程细想》的时候,看完了这个学期都已经结束了 好吧,按照自己的计划,开始适应一段时间,每天坚持记笔记,对了,还忘了一项,每天跑步 经过一个星期的努力挣扎我决定先看设计模式,也不能说要研究一下,毕竟我接触java的时间还是很短的,本着先简单的了解,懂得一下,然后在慢慢看java编程思想,而把后两者当做一个学习工具来用,还是这样学习吧。 最近初学设计模式,就申请了一个专栏,旨在交流经验,请大家批评指正初学中的错误 基本学习路线是看手头上的一部书,然后在google检索10篇相关文章,然后再根据自己理解做笔记(这个词关键落在了笔记,因为是初学设计模式,希望大家多多指点) 里面相关的UML的东西,我简单的理解源于 [http://blog.csdn.net/zhengzhb/article/details/7187278](http://blog.csdn.net/zhengzhb/article/details/7187278) 希望对大家有帮助,还有我觉得一个很不错的专栏 [http://blog.csdn.net/column/details/pattern.html](http://blog.csdn.net/column/details/pattern.html) 学习过程中用的软件 Eclipse(官网下载地址) [http://eclipse.org](http://eclipse.org) jude下载地址 [http://download.csdn.net/detail/wclxyn/4226796](http://download.csdn.net/detail/wclxyn/4226796) startUML下载地址 [http://download.csdn.net/detail/wclxyn/4226812](http://download.csdn.net/detail/wclxyn/4226812) UML学习视频下载地址: [http://www.verycd.com/topics/2873230/](http://www.verycd.com/topics/2873230/) 好吧,现在开始共同学习共同进步,之后等24种模式(简单工厂模式不算23种模式之一,所以这里总结了24种)写完了把目录和参考文献和源码贴到这里
';

前言

最后更新于:2022-04-01 15:48:00

> 原文出处:[初学设计模式](http://blog.csdn.net/column/details/first-study-pattern.html) 作者:[wclxyn](http://blog.csdn.net/wclxyn) **本系列文章经作者授权在看云整理发布,未经作者允许,请勿转载!** # 初学设计模式 > 最近初学设计模式,就申请了一个专栏,旨在交流经验,请大家批评指正初学中的错误。坚持每天学一个模式,这个模式主要是针对java的
';