组合模式
总结关于组合模式的目的:
客户程序可以向处理简单元素一样来处理复杂元素。
关于组合模式的作用:
可用于处理对象的部分-整体结构,经常用于处理拥有树状结构的问题。
对应的类图:
下列贴一段代码来说明应用组合模式+迭代器来模拟对树的遍历,顺便复习了数据结构中的树相关知识。本代码参考网上相关代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | /** * 结点接口 * @author ChenST */ public interface Node { /** * 添加结点 * @param node */ public void add(Node node); /** * 获取一个迭代器 * @return */ public Iterator<Node> iterator(); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | /** * 抽象结点,主要实现toString方法,可用于识别各个结点 * @author ChenST * */ public abstract class AbstractNode implements Node{ /** 结点名字 */ protected String nodeName; public AbstractNode(String nodeName){ this .nodeName = nodeName; } public String toString(){ return nodeName; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /** * 叶子结点,不允许有子结点 * @author ChenST */ public class LeafNode extends AbstractNode { public LeafNode(String nodeName) { super (nodeName); } @Override public void add(Node node) { throw new UnsupportedOperationException( "叶子结点不能添加结点" ); } @Override public Iterator<Node> iterator() { //返回空的迭代器,永远无法进行迭代 return new NullIterator<Node>(); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | /** * 枝结点,可存储多数叶子结点 * @author ChenST */ public class BranchNode extends AbstractNode { //树枝结点下的所有孩子结点 private List<Node> childs = new ArrayList<Node>(); public BranchNode(String nodeName) { super (nodeName); } @Override public void add(Node node) { childs.add(node); } @Override public Iterator<Node> iterator() { return childs.iterator(); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | /** * 空的迭代器 * @author ChenST * * @param <T> */ public class NullIterator<T> implements Iterator<T> { @Override public boolean hasNext() { //永远没有下一个结点 return false ; } @Override public T next() { //永远为空 return null ; } @Override public void remove() { //没有移除方法 } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | /** * 深度优先迭代器 * @author ChenST */ public class DepthFirstIterrator implements Iterator<Node> { //堆栈 private Stack<Iterator<Node>> stack = new Stack<Iterator<Node>>(); public DepthFirstIterrator(Iterator<Node> iter){ this .stack.push(iter); } @Override public boolean hasNext() { if (stack.isEmpty()){ return false ; } else { Iterator<Node> iter = this .stack.peek(); if (iter.hasNext()){ return true ; } else { this .stack.pop(); return hasNext(); } } } @Override public Node next() { if (hasNext()){ Iterator<Node> iter = this .stack.peek(); Node node = iter.next(); if (node instanceof BranchNode){ this .stack.push(node.iterator()); } return node; } return null ; } @Override public void remove() { throw new UnsupportedOperationException( "不支持移除操作" ); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | /** * 广度优先算法的迭代器 * @author ChenST */ public class BreadthFirstIterator implements Iterator<Node> { //存储临时结点操作的队列 private Queue<Iterator<Node>> queue = new LinkedList<Iterator<Node>>(); public BreadthFirstIterator(Iterator<Node> iter){ queue.offer(iter); } @Override public boolean hasNext() { if (queue.isEmpty()){ return false ; } else { Iterator<Node> iter = queue.peek(); if (iter.hasNext()){ return true ; } else { queue.poll(); return hasNext(); } } } @Override public Node next() { if (hasNext()) { Iterator<Node> it = queue.peek(); Node node = it.next(); if (node instanceof BranchNode){ queue.offer(node.iterator()); } return node; } return null ; } @Override public void remove() { throw new UnsupportedOperationException( "不支持移除操作" ); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | public class Test { public static void main(String[] args) { //构建树 Node A = new BranchNode( "A" ); Node B = new BranchNode( "B" ); Node C = new BranchNode( "C" ); Node D = new BranchNode( "D" ); Node E = new LeafNode( "E" ); Node F = new LeafNode( "F" ); Node G = new LeafNode( "G" ); Node K = new LeafNode( "K" ); A.add(B); A.add(C); B.add(D); B.add(E); C.add(F); D.add(G); D.add(K); //深度优先迭代器 System.out.print( "深度优先迭代器:" +A); Iterator<Node> iterDepth = new DepthFirstIterrator(A.iterator()); while (iterDepth.hasNext()){ System.out.print(iterDepth.next()); } //广度优先迭代器 Iterator<Node> iterBreadth = new BreadthFirstIterator(A.iterator()); System.out.print( "\n广度优先迭代器:" +A); while (iterBreadth.hasNext()){ System.out.print(iterBreadth.next()); } } } |
1 2 | 深度优先迭代器:ABDGKECF 广度优先迭代器:ABCDEFGK |
本例子利用自定义迭代器(深度优先迭代器和广度优先迭代器)对构建的树进行了访问。可以看到利用组合模式不管对叶子结点访问还是对整颗树进行访问或者对树的某个子树进行访问都是用同样的方法都可以达到目的。这就是组合模式的核心。
桥接模式
关于桥接模式的定义:
将抽象与行为相分离,使得他们各自可以独立变化,然后可通过动态组合得到想要的结果,目标是实现解耦。桥接模式的类关系图如下:
现在举一个例子来说明桥接模式.
以最常用的咖啡问题来说明。现在模拟的场景是这样子的:
咖啡有分大杯和中杯,同时咖啡里面可以选择加牛奶,也可以选择加苹果汁,也可以什么都不加。因为刚开张,所以目前就只有大杯和中杯,未来可能会有更多规格的杯子,同时也会有更多的调料给客人选择,设计一个具有弹性的程序 |
分析:按照目前的情况,最简单的做法就是分别写出6种类,来表示六种不同组合的咖啡。
我们可以分析到这种做法虽然和直观,但是会存在很多问题,其中之一就是这6个类的每一个类都已经具体的代表了一种咖啡,换句话说,这几个类是没办法复用的,这当然是我们不想要的,另外一个问题就是,如果添加一个规格的杯子,比如小杯,又要再写小杯中分别加不同调料的类,可想而知,后面店的规模大起来的话,会造成类的“炸弹”。
我们想要的结果是,当增加一种调料时只需要增加一个类,增加一个杯子规模的时候也只需要增加一个类就可以达到目的,这就需要用到桥接模式了。
桥接模式分析法:把属性和行为分别抽象并独立开来,行为就是加牛奶加苹果汁等,属性就是大杯中杯之类的。我们的目的就是把行为和属性完全没有耦合,通过组合来形成不同的咖啡,通俗点说,例如我们只提供的各种零件,让使用者去使用而已,不提供整合好的东西。
请看分析的类图:
具体来看看代码的实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 | /** * 咖啡的行为 * @author ChenST * */ public interface Action { /** * 做事情 * @return */ public String doThing(); } |
1 2 3 4 5 6 7 8 9 10 11 | /** * 加牛奶的行为 * @author ChenST */ public class AddMilkAction implements Action { @Override public String doThing() { return "加了[牛奶]" ; } } |
1 2 3 4 5 6 7 8 9 10 11 | /** * 什么也不加的行为 * @author ChenST */ public class EmptyAction implements Action { @Override public String doThing() { return "什么也没加" ; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 | /** * 加了苹果汁 * @author ChenST * */ public class AddAppleAction implements Action { @Override public String doThing() { return "加了[苹果汁]" ; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | /** * 咖啡抽象类 * @author ChenST */ public abstract class Coffee { private Action action; public Coffee(Action action){ this .action = action; System.out.println( this .result()); } public Action getAction(){ return action; } /** * 得到的咖啡结果 * @return */ public abstract String result(); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | /** * 大杯咖啡 * @author ChenST */ public class BigCupCoffe extends Coffee { public BigCupCoffe(Action action){ super (action); } @Override public String result() { String thing = this .getAction().doThing(); return "[大杯]" +thing+ "的咖啡" ; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | /** * 中杯咖啡 * @author ChenST * */ public class MiddleCupCoffee extends Coffee { public MiddleCupCoffee(Action action){ super (action); } @Override public String result() { String thing = this .getAction().doThing(); return "[中杯]" +thing+ "的咖啡" ; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | public class Test { public static void main(String[] args) { //加牛奶的大杯咖啡 Coffee coffee1 = new BigCupCoffe( new AddMilkAction()); //什么也没加的大杯咖啡 Coffee coffee2 = new BigCupCoffe( new EmptyAction()); //加苹果汁的大杯咖啡 Coffee coffee3 = new BigCupCoffe( new AddAppleAction()); //加牛奶的中杯咖啡 Coffee coffee4 = new MiddleCupCoffee( new AddMilkAction()); //什么也没加的中杯咖啡 Coffee coffee5 = new MiddleCupCoffee( new EmptyAction()); //加苹果汁的中杯咖啡 Coffee coffee6 = new MiddleCupCoffee( new AddAppleAction()); } } |
1 2 3 4 5 6 | [大杯]加了[牛奶]的咖啡 [大杯]什么也没加的咖啡 [大杯]加了[苹果汁]的咖啡 [中杯]加了[牛奶]的咖啡 [中杯]什么也没加的咖啡 [中杯]加了[苹果汁]的咖啡 |
代理模式-静态代理
相对于动态代理,静态代理好理解多了。
看静态代理涉及的角色以及相关关系图
再来看看代码实现,(相关知识写在代码注释中了~呵~)
1 2 3 4 5 | //抽象对象 public interface ISubject { public void request(); } |
1 2 3 4 5 6 7 8 | //真实对象,实现类 public class SubjectImpl implements ISubject{ @Override public void request() { System.out.println( "hello world" ); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | //代理对象 ,代理对象和实际对象都实现了抽象对象 //这样的好处,可以用代理对象来完成相应的操作, //也可以用实际对象来完成操作 //某些情况,就是不想通过实际对象去完成操作, //要交给代理对象去完成相应的操作. public class SubjectProxy implements ISubject { //组合真实对象 private ISubject subject = new SubjectImpl(); @Override public void request() { //在执行实际对象的request之前,还可以做一些其他操作 //是不是很像Spring 中的AOP啊 //-------------------------- //实际上是调用真实对象的request //只是这是代理对象帮忙去调用reqeust //很符合实际中的代理意义 subject.request(); //-------------------------- //还可以在实际对象操作结束之后,做一些其他操作 } } |
1 2 3 4 5 6 7 | public class Test { public static void main(String[] args) { ISubject proxy = new SubjectProxy(); proxy.request(); } } |
完成,可以看到静态代理和动态代理的区别,静态代理,一个真实对象对应一个代理,如果有很多个真实对象需要代理,那么就需要很多个代理对象了,而动态代理的作用就在于此,他有一个总代理,可由代理工厂根据进入的代理类来得到代理对象。
呵呵~~
代理模式-动态代理
最近项目中一直在配置Spring AOP,听说AOP是基于动态代理模式实现的,于是乎就去学习了动态代理,虽然还是迷迷糊糊,不过还是将自己的学习成功总结下。
自己写了个例子来说明:(部分说明写在代码中)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //汽车类 public class Car { //牌子 private String brand; public Car(String brand){ this .brand = brand; } //获取汽车的描述 public String getDescribe(){ return brand+ "车" ; } } |
1 2 3 4 5 6 7 | //奥迪车 public class AudiCar extends Car{ public AudiCar(){ super ( "奥迪" ); } } |
1 2 3 4 5 6 7 | //奔驰车 public class BenzCar extends Car { public BenzCar(){ super ( "奔驰" ); } } |
1 2 3 4 5 | //汽车代理接口 public interface CarProxy { public void sellCar(Car car); } |
1 2 3 4 5 6 7 8 | //汽车代理实现类 public class CarProxyImpl implements CarProxy { @Override public void sellCar(Car car){ System.out.println( "卖出一辆" +car.getDescribe()); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | //动态代理对象(调用处理器)-可代理任何的代理对象 //这个类是被java.lang.reflect.Proxy所调用 public class DynamicProxy implements InvocationHandler{ //代理对象 private Object proxyObject; public DynamicProxy(Object proxyObject){ this .proxyObject = proxyObject; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //方法执行前做事 Spring AOP 切面的原理 ,对方法method进行横切 //在真正执行方法之前或者之后做一些额外的操作 //就这就Spring AOP实现横向切面的原理了 System.out.println( "打算执行方法" ); Object object = method.invoke(proxyObject, args); //方法执行之后做的事,Spring AOP 切面的原理 System.out.println( "方法执行之后" ); return object; } } |
1 2 3 4 5 6 7 8 9 10 11 | //代理工厂 public class ProxyFactory { // 创建一个代理 public static Object createProxy(Object proxyObject) { // 被代理的对象 Class<? extends Object> clazz = proxyObject.getClass(); Object proxy = Proxy.newProxyInstance(clazz.getClassLoader(), clazz .getInterfaces(), new DynamicProxy(proxyObject)); return proxy; } } |
1 2 3 4 5 6 7 8 9 10 11 | //测试类 public class Test { public static void main(String[] args) { //通过代理工厂创建一个汽车代理 CarProxy carProxy = (CarProxy) ProxyFactory .createProxy( new CarProxyImpl()); carProxy.sellCar( new AudiCar()); carProxy.sellCar( new BenzCar()); } } |
1 2 3 4 5 6 | 打算执行方法 卖出一辆奥迪车 方法执行之后 打算执行方法 卖出一辆奔驰车 方法执行之后 |
动态代理的好处就是可以代理任意的代理对象,都可以通过代理工厂中指定代理对象即可。
另外就是可对执行方法加入一些额外操作,就是AOP了,只是Spring把这些都通过配置来实现。
设计模式之Builder模式
前两天,看的Google Collections 的集合组件,看了源代码,发现很多东西都是使用builder来创建,今天也上网查了些东西学习学习,发现多看看开源的源代码还是挺有好处的。今天模仿着Google Collections里面的东东写了一个Demo,呵呵,和标准的Builder模式写法不太相同,不过思想是一样的。贴个Demo程序就好了,模拟一个Bean对象的创建。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | //Builder模式的角色:[Product]要生产的最终物品 /** * 用户对象 */ public class User { // 用户名 private String userName; // 用户密码 private String password; // 用户姓名 private String name; // 可看做[Director] 产流水线,负责产品的生产和组织 private User(Builder builder){ this .userName = builder.userName; this .password = builder.password; this .name = builder.name; } //getter方法 public String getUserName() { return userName; } public String getPassword() { return password; } public String getName() { return name; } // Builder模式的角色:[Builder]能进行生产的工作和获得生产的结果 /** * 创建该用户的建立者 * @param userName 用户名 * @return Builder对象 */ public static Builder builder(String userName){ return new Builder(userName); } // 创建者对象 public static final class Builder{ // Builder模式的角色:[Part]产品的基本组成部分 //用户名无法更改 private final String userName ; //密码 private String password; //真实姓名 private String name; //创建对象时必须指定用户名 public Builder(String userName){ this .userName = userName; } /** * 设置密码 * @param password 密码 * @return Builder对象 */ public Builder setPassword(String password){ this .password = password; return this ; } /** * 设置姓名 * @param name 真实姓名 * @return Builder对象 */ public Builder setName(String name){ this .name = name; return this ; } /** * 创建用户对象 * @return 用户对象 */ public User build(){ //这里在创建对象之前可以进行验证性操作, //而单纯的Bean对象不能进行验证性操作. //普通的做法:User user = new User(); user.setXXX()... //普通的做法使得创建对象和对对象的赋值操作分离开来 //如果用户名为空,则无法创建该对象 if (userName == null || userName.isEmpty()){ throw new IllegalArgumentException( "用户名为空,无法创建对象" ); } return new User( this ); } } } |
看Builder创建过程:
1 2 3 4 5 6 7 8 9 10 11 12 | public class Test { public static void main(String[] args) { User.Builder builder = User.builder( "cst" ); builder.setName( "chenshuting" ); builder.setPassword( "123" ); User user = builder.build(); System.out.println(user.getUserName()); System.out.println(user.getPassword()); System.out.println(user.getName()); } } |
继续学习ing~~~~
迭代器模式--回答历史性问题
记得以前春哥问我:为什么迭代器都能够遍历多种数据结构,是怎么实现的呢。?
今天有空,看了迭代器模式,研究了几个小时的JDK~~总结如下:
先来看看一个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | List<String> list= new ArrayList<String>(); list.add( "a" ); list.add( "b" ); list.add( "c" ); Iterator<String> iter=list.iterator(); while (iter.hasNext()){ System.out.println(iter.next()); } //遍历Vector List<String> vec= new Vector<String>(); vec.add( "d" ); vec.add( "e" ); vec.add( "f" ); Iterator<String> iterv=vec.iterator(); while (iterv.hasNext()){ System.out.println(iterv.next()); } |
为什么一个方法能够遍历不同集合呢。?
看下它们的关系图就可以知道原理了,而且使用的是迭代器模式。
纯粹是纪念下午的研究结果~~
状态模式
定义摘自《head first》中:
状态模式:允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。
对于使用者来说看起来好像是能够修改自己的类,实际上是委托状态对象来改变相关操作。
状态模式类图如下(截图于《head first》):
对于状态模式,我自己举了例子:描述一个人经过外界时间的影响,心情状态会有不同的变化。
例如:一个人捡到钱了,当然是很高兴,钱丢了当然就不高兴也就是悲伤了,当丢的钱又捡回来了,于是就从悲伤变成高兴了。
看下面状态图:
使用状态模式实现,代码如下:
1.状态接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | /** * 状态接口 * * @author ChenST * * @create 2010-3-25 */ public abstract class State { /** 状态名 */ private String name; /** * 捡到钱了 */ public abstract void pickMoney(); /** * 丢钱了 */ public abstract void loseMoney(); /** * 钱捡回来了 */ public abstract void backMoney(); public String getName() { return name; } public void setName(String name) { this .name = name; } } |
2.正常状态
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | /** * 正常状态 * * @author Administrator * * @create 2010-3-25 */ public class NormalState extends State { /** 该状态所发生的实体 */ private Person person; public NormalState(Person person) { this .person=person; this .setName( "正常" ); } public void loseMoney() { //丢钱了,很悲伤,状态转变 System.out.println( "钱丢啦!" ); person.setCurrent(person.getSad()); } public void pickMoney() { System.out.println( "捡到钱了!" ); person.setCurrent(person.getHappy()); } public void backMoney() { //无状态改变 } } |
3.高兴状态
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | /** * 高兴的状态 * * @author ChenST * * @create 2010-3-25 */ public class HappyState extends State { /** 该状态所发生的实体 */ private Person person; public HappyState(Person person) { this .person=person; this .setName( "高兴" ); } public void backMoney() { //无任何状态改变 } public void loseMoney() { //无任何状态改变 } public void pickMoney() { //无任何状态改变 } } |
4.悲伤状态
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | /** * 悲伤状态 * * @author ChenST * * @create 2010-3-25 */ public class SadState extends State { /** 该状态所发生的实体 */ private Person person; public SadState(Person person) { this .person=person; this .setName( "悲伤" ); } public void backMoney() { //丢失的钱失而复得,很高兴 System.out.println( "捡回来了,原来丢在这儿了" ); person.setCurrent(person.getHappy()); } public void loseMoney() { //无状态改变 } public void pickMoney() { //无状态改变 } } |
5.人类,状态存在的实体
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | /** * 一个人的类 * * @author ChenST * * @create 2010-3-25 */ public class Person extends State{ /** 高兴的状态 */ private State happy; /** 悲伤的状态 */ private State sad; /** 正常的状态 */ private State normal; /** 当前的状态 */ private State current; public Person(){ this .happy= new HappyState( this ); this .sad= new SadState( this ); this .normal= new NormalState( this ); //当前状态为正常状态 this .current= this .normal; } /** * 显示打印当前状态 */ public void showCurrentState(){ System.out.println(current.getName()); } /** * 重新设置状态,回复默认状态 */ public void resetState(){ this .current= this .normal; } // //委托给状态对象去执行操作 // public void backMoney() { current.backMoney(); } public void loseMoney() { current.loseMoney(); } public void pickMoney() { current.pickMoney(); } public State getCurrent() { return current; } public void setCurrent(State current) { this .current = current; } public State getHappy() { return happy; } public void setHappy(State happy) { this .happy = happy; } public State getNormal() { return normal; } public void setNormal(State normal) { this .normal = normal; } public State getSad() { return sad; } public void setSad(State sad) { this .sad = sad; } } |
6.测试类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | /** * 测试类 * * @author ChenST * * @create 2010-3-25 */ public class Test { public static void main(String[] args) { //今天詹姆斯出去买东西 Person james= new Person(); james.pickMoney(); //今天运气好,捡到钱了 james.showCurrentState(); //查看下詹姆斯的心情 james.resetState(); //于是不买东西了回家了.(恢复默认状态) james.showCurrentState(); //查看下詹姆斯的心情 //第二天詹姆斯又出去买东西 james.loseMoney(); //今天运气不好,丢钱了 james.showCurrentState(); //查看下詹姆斯的心情 james.backMoney(); //今天运气还不算很差,钱捡回来了。 james.showCurrentState(); //查看下詹姆斯的心情 } } |
7.运行结果
1 2 3 4 5 6 7 | 捡到钱了! 高兴 正常 钱丢啦! 悲伤 捡回来了,原来丢在这儿了 高兴 |
OK~~完毕~可以看到,如果对状态的增加或者修改,或者对行为的增加或修改,都可以很好的扩展和维护。只要在人的类里面增加相应的状态和方法即可改变,而不需要改变整体结构,用增加类来代替if 的条件判断。
外观模式
今天,做完了公司的课题,无聊之余总结下之前的【外观模式】,看了这个模式的具体内容,很早以前就有用这样的思想了,只是不知道它叫外观模式。外观模式:实际上是提供一个经常使用的接口,这个接口他执行了许多子系统中的许多操作,使得用户不需要了解子系统中的具体操作,只需使用接口。这种例子是很常见的。
例如:我们知道用户、角色、权限三者关系,在早期,还没有角色的概念,只有用户和权限的概念,是直接讲权限赋予用户,但是后来为了方便管理,才引入角色的概念,把权限赋予角色,再把角色赋予用户。而角色就是我们外观模式中说的经常使用的接口,权限就是子系统,用户就是客户。
看下面的两个等价图:
1.有角色参与:
2.无角色参与:
可以看到,使用外观模式使的客户使用更方便,不需要了解子系统的过程,整个层次也更清晰。
无聊的实现了下这个代码:贴个纪念~~
1.权限类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /** * 权限类 * * @author ChenST * * @create 2010-3-24 */ public class Right { /** 【添加】的权限 */ public final static String ADD_RIGHT= "【添加】" ; /** 【删除】的权限 */ public final static String DELETE_RIGHT= "【删除】" ; /** 【更新】的权限 */ public final static String UPDATE_RIGHT= "【更新】" ; /** 【查看】的权限 */ public final static String SEE_RIGHT= "【查看】" ; } |
2.角色抽象类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | /** * 角色抽象类 * * @author ChenST * * @create 2010-3-24 */ public abstract class Role { /** 角色拥有的权限*/ private Set<String> rights; public Role(){ this .rights= new HashSet<String>(); //赋权操作 this .addRight(); } /** * 添加权限 */ public abstract void addRight(); public Set<String> getRights() { return rights; } } |
3.管理员角色
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | /** * 超级管理员角色 * * @author ChenST * * @create 2010-3-24 */ public class Admin extends Role{ /* * 添加全部的权限 * (non-Javadoc) * @see facade.Role#addRight() */ @Override public void addRight() { this .getRights().add(Right.ADD_RIGHT); this .getRights().add(Right.DELETE_RIGHT); this .getRights().add(Right.SEE_RIGHT); this .getRights().add(Right.UPDATE_RIGHT); } } |
4.会员用户
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /** * 会员用户 * * @author ChenST * * @create 2010-3-24 */ public class Vip extends Role { /* * 会员用户拥有【添加】权限 * (non-Javadoc) * @see facade.Role#addRight() */ @Override public void addRight() { this .getRights().add(Right.ADD_RIGHT); } } |
5.普通用户角色
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /** * 普通用户角色 * * @author ChenST * * @create 2010-3-24 */ public class CommonUser extends Role{ /* * 普通用户只拥有【查看】的权限 * (non-Javadoc) * @see facade.Role#addRight() */ @Override public void addRight() { this .getRights().add(Right.SEE_RIGHT); } } |
5.用户类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | /** * 用户 * * @author ChenST * * @create 2010-3-24 */ public class User { /** 用户姓名 */ private String name; /** 用户所拥有的角色 */ private Set<Role> roles; public User(String name){ this .name=name; roles= new HashSet<Role>(); } /** * 添加权限 * @param role */ public void addRole(Role role){ this .roles.add(role); } /** * 查看用户所拥有的权限 */ public void lookRight(){ System.out.println( this .name+ "权限有:" + this .getRights()); } /** * 获取用户所拥有的权限 * @return */ public Set<String> getRights() { Set<String> rights= new HashSet<String>(); for (Role role : roles) { for (String right: role.getRights()) { rights.add(right); } } return rights; } } |
6.测试类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | /** * 测试类 * * @author ChenST * * @create 2010-3-24 */ public class Test { public static void main(String[] args) { //创建用户james和green User james= new User( "james" ); User green= new User( "green" ); User joe= new User( "joe" ); //创建三个角色 超级管理员,普通管理员,普通用户 Role admin= new Admin(); Role vip= new Vip(); Role commonUser= new CommonUser(); //给james赋予角色,赋予管理员和普通用户 james.addRole(admin); james.addRole(commonUser); //给green赋予角色,赋予管理员 green.addRole(admin); //给joe赋予角色,赋予管理员和会员 joe.addRole(vip); joe.addRole(admin); //查看拥有的权限 james.lookRight(); green.lookRight(); joe.lookRight(); } } |
运行结果:
1 2 3 | james权限有:[【删除】, 【更新】, 【查看】, 【添加】] green权限有:[【删除】, 【更新】, 【查看】, 【添加】] joe权限有:[【删除】, 【更新】, 【查看】, 【添加】] |
可以看到,对于角色很好扩展和维护,对于权限的分配也可以很好维护,例如,会员用户要添加一个新的权限,那么则只要修改会员用户的权限,而不需要把相关的用户全部修改。OK~~
适配器模式
适配器模式:顾名思义,就是由一个中间介质,实现一种接口到另外一种接口的转化。两种接口都不用改变其中任何一个接口的结构。
适配器模式成为【类适配器】和【对象适配器】,这里用java实现,因此只讨论【对象适配器】,结构看下图:
举个例子,今天插在笔记本的鼠标坏了,叫小妹去买个鼠标,可是买回来才发现,她居然买了个PS2接口的鼠标,可是我笔记本是USB接口的呀,这要怎么用啊。?
如果再买个USB的鼠标,那么这个就浪费了,很明显我是不想换鼠标。更不想把笔记本给换成台式的吧~,于是这个时候我们就想到了用转换器,即实现USB到PS2的转换,代码实现如下:
1.USB接口
1 2 3 4 5 6 7 8 9 10 11 12 | /** * USB接口 * * @author ChenST * * @create 2010-3-23 */ public interface USB { /** 产品描述 */ public void describe(); } |
2.PS2接口
1 2 3 4 5 6 7 8 9 10 11 12 | /** * PS2接口【鼠标圆孔接口】 * * @author ChenST * * @create 2010-3-23 */ public interface PS2 { /** 产品描述 */ public void describe(); } |
3.鼠标类
1 2 3 4 5 6 7 8 9 10 11 12 13 | /** * 鼠标类,实现了PS2接口,即【圆孔的鼠标】 * * @author ChenST * * @create 2010-3-23 */ public class Mouse implements PS2 { public void describe() { System.out.println( "用的是PS2接口" ); } } |
4.适配器(USB和PS2的转换器)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | /** * 接口适配器,拥有USB接口 * * @author ChenST * * @create 2010-3-23 */ public class Adapter implements USB{ /** PS2接口 */ private PS2 ps2; public Adapter(PS2 ps2) { this .ps2=ps2; } public void describe() { ps2.describe(); } } |
5.测试类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | /** * 测试类 * 买了一个圆孔鼠标想要插笔记本上,却发现笔记本上没有圆孔, * 只有USB接口,这个鼠标好贵啊,再买个圆孔鼠标经济上是不可行的, * 更不能扔了笔记本而换台式的电脑把。于是想到使用USB和PS2转化器 * 将转化器插在笔记本电脑上,于是笔记本USB接口就变成了PS2接口了, * 此时鼠标就可以接入了。 * * @author ChenST * * @create 2010-3-23 */ public class Test { public static void main(String[] args) { //圆孔鼠标 PS2 mouse= new Mouse(); //适配器,把他变成鼠标要用的接口 Adapter adapter= new Adapter(mouse); //现在查看下原来是USB的接口的适配器用的是什么接口 adapter.describe(); } } |
运行结果:
1 | 用的是PS2接口 |
从结果可以看出,适配器已经实现了从USB接口到PS2接口的转换了~~OK~又学习了一个新模式
模版方法模式
模版方法模式,简单来说就是封装了算法的骨架,将一些可变的部分延迟到之类中实现。
模版方法模式使得子类可以不改变一个算法的结构即可重新定义该算法的某些特定的步骤。
模版方法模式的结构图如下:
以一个例子来说明模版模式吧,也是参考网上总结的。
我们知道,两个人从认识到结婚,是要经历一些过程的,比如初次见面、吃饭、约会、婚礼等一系列过程,每个人都要经历这些阶段,但是每个人的这些过程实现都是不一样的,典型的特例,以穷人和富人,他们实施这些事情的时候,具体肯定是不一样的。请看代码:
1.婚恋的抽象类。【模版类】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | /** * 一个【爱】的抽象类,描述了属于两个人婚恋的过程, * 从相遇到吃饭,到约会,最后到结婚 * * @author ChenST * * @create 2010-3-22 */ public abstract class Love { /** * 两个人见面的过程 */ public abstract void meet(); /** * 两个人吃饭的过程 */ public abstract void dinner(); /** * 两个人约会的过程 */ public abstract void appointment(); /** * 两个人结婚的过程 */ public abstract void wedding(); /** * 两个人爱情的一个模版(模版方法)//final为了不被之类覆盖 */ public final void loveTemplate(){ if ( this .doMarray()){ this .meet(); this .dinner(); this .appointment(); this .wedding(); } } /** * 两个人是否要结婚,是的话返回true,否则返回false (钩子方法) * 可由子类来控制 * @return */ public boolean doMarray(){ return true ; } } |
2.【穷人】的婚恋过程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | /** * 【穷人】的恋爱过程 * * @author ChenST * * @create 2010-3-22 */ public class PoolerLove extends Love { @Override public void appointment() { System.out.println( "去爬免费的山,当作运动!" ); } @Override public void dinner() { System.out.println( "去沙县吃扁肉拌面!" ); } @Override public void meet() { System.out.println( "借了一套西装,与女孩见面!" ); } @Override public void wedding() { System.out.println( "摆一桌酒,一家人吃的开开心心!" ); } } |
3.【富人】的婚恋过程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | /** * 【富人】的婚恋过程 * * @author ChenST * * @create 2010-3-22 */ public class RicherLove extends Love{ @Override public void appointment() { System.out.println( "玩遍中国的大江南北,爱国!" ); } @Override public void dinner() { System.out.println( "天天吃香格里拉!" ); } @Override public void meet() { System.out.println( "穿名牌西装,约在香格里拉酒店见面!" ); } @Override public void wedding() { System.out.println( "婚礼全国直播!" ); } } |
4.测试类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | /** * 测试类 * * @author ChenST * * @create 2010-3-22 */ public class Test { public static void main(String[] args) { System.out.println( "穷人恋爱过程" ); //穷人恋爱过程 Love pooler= new PoolerLove(); //调用恋爱模版 pooler.loveTemplate(); System.out.println( "\n富人恋爱过程" ); //富人恋爱过程 Love richer= new RicherLove(); //调用恋爱模版 richer.loveTemplate(); } } |
5.运行结果:
1 2 3 4 5 6 7 8 9 10 11 | 穷人恋爱过程 借了一套西装,与女孩见面! 去沙县吃扁肉拌面! 去爬免费的山,当作运动! 摆一桌酒,一家人吃的开开心心! 富人恋爱过程 穿名牌西装,约在香格里拉酒店见面! 天天吃香格里拉! 玩遍中国的大江南北,爱国! 婚礼全国直播! |
可以看到结果,模版方法的好处就是,你还可以根据自己的特点,实现自己的婚恋过程,只需调用恋爱模版即可~~