其实每个设计模式都是很重要的一种思想,看上去很熟,其实是因为我们在学到的东西中都有涉及,尽管有时我们并不知道,其实在Java本身的设计之中处处都有体现,像AWT、JDBC、集合类、IO管道或者是Web框架,里面设计模式无处不在。本章不出意外的话,应该是设计模式最后一讲了,首先还是上一下上篇开头的那个图:
本章讲讲第三类和第四类。
19、备忘录模式(Memento)
主要目的是保存一个对象的某个状态,以便在适当的时候恢复对象,个人觉得叫备份模式更形象些,通俗的讲下:假设有原始类A,A中有各种属性,A可以决定需要备份的属性,备忘录类B是用来存储A的一些内部状态,类C呢,就是一个用来存储备忘录的,且只能存储,不能修改等操作。做个图来分析一下:
Original类是原始类,里面有需要保存的属性value及创建一个备忘录类,用来保存value值。Memento类是备忘录类,Storage类是存储备忘录的类,持有Memento类的实例,该模式很好理解。直接看源码:
package memeto;
public class Original {
private String value1;
private String value2;
Memento createMemento(){
Memento memento = new Memento(this);
return memento;
}
public String getValue1() {
return value1;
}
public void setValue1(String value1) {
this.value1 = value1;
}
public String getValue2() {
return value2;
}
public void setValue2(String value2) {
this.value2 = value2;
}
void restoreValue(Memento mentome){
this.value1=mentome.getValue1();
}
}
package memeto;
public class Storage {
private Memento memento;
public Storage(Memento memento){
this.memento = memento;
}
public Memento getMemento(){
return this.memento;
}
}
package memeto;
public class Memento {
private Original original;
private String value1;
public Memento(Original original){
this.original = original;
this.value1 = original.getValue1();
}
public String getValue1() {
return value1;
}
}
演示:
package memeto;
/**
* “备份-恢复”模式
*/
public class Test {
public static void main(String[] args) {
Original original = new Original();
original.setValue1("original保存的");
original.setValue2("original没有保存的");
Memento memento = original.createMemento();
Storage storage = new Storage(memento);
Memento memento1 = storage.getMemento();//memento1指向刚才被存储的备忘录
System.out.println(original.getValue1());//刚开始被保存的
original.setValue1("original保存的被修改啦!!");
System.out.println(original.getValue1());//修改后的
original.restoreValue(memento1);
System.out.println(original.getValue1());//恢复后的
}
}
简单描述下:新建原始类时,value被初始化为original保存的,后经过修改,将value的值置为original保存的被修改啦!!
,最后倒数第二行进行恢复状态,结果成功恢复了。其实我觉得这个模式叫“备份-恢复”模式最形象。
20、状态模式(State)
核心思想就是:当对象的状态改变时,同时改变其行为,很好理解!就拿QQ来说,有几种状态,在线、隐身、忙碌等,每个状态对应不同的操作,而且你的好友也能看到你的状态,所以,状态模式就两点:1、可以通过改变状态来获得不同的行为。2、你的好友能同时看到你的变化。
State类是个状态类,Context类可以实现切换,我们来看看代码:
package state;
public class State {
public String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public void method1(){
System.out.println("method1 excute");
}
public void method2(){
System.out.println("method2 excute");
}
}
package state;
public class Context {
private State state;
public Context(State state){
this.state = state;
}
public void method(){
if (state.getValue().equals("state1")) {
state.method1();
} else if (state.getValue().equals("state2")) {
state.method2();
}
}
}
package state;
/**
* 当对象的状态改变时,同时改变其行为,很好理解!就拿QQ来说,有几种状态,在线、隐身、忙碌等,
* 每个状态对应不同的操作,而且你的好友也能看到你的状态,所以,状态模式就两点:
* 1、可以通过改变状态来获得不同的行为。2、你的好友能同时看到你的变化。
* 跟策略模式区别还是状态的问题 状态根据某个东西会改变的 虽然也是选择算法 而策略是根据某个东西选择算法 本身这个东西不变
*/
public class Test {
public static void main(String[] args) {
State state = new State();
Context context = new Context(state);
//设置第一种状态
state.setValue("state1");
context.method();
//设置第二种状态
state.setValue("state2");
context.method();
}
}
根据这个特性,状态模式在日常开发中用的挺多的,尤其是做网站的时候,我们有时希望根据对象的某一属性,区别开他们的一些功能,比如说简单的权限控制等。
这里本来想用该模式实现会员根据不同等级获得不同商品的价格的切换 发现该模式缺点在于当前一个会员只有一个等级 你不会总去改变他的等级来实现商品的不同价格,且获得商品不同价格的方式比较没有扩展性 没有策略模式实现的方便
贴一下代码
package state.member;
public class Goods {
public Integer price;
public Integer getPrice() {
return price;
}
public void setPrice(Integer price) {
this.price = price;
}
}
package state.member;
public class Member {
public String memberLevel;
public String getMemberLevel() {
return memberLevel;
}
public void setMemberLevel(String memberLevel) {
this.memberLevel = memberLevel;
}
}
package state.member;
public class Context {
private Member member;
public Context(Member member){
this.member = member;
}
public Integer price(Goods goods){
if(member.getMemberLevel()==null||member.getMemberLevel().equals("普通会员")){
}
else if(member.getMemberLevel().equals("黄金会员")){
goods.setPrice(100);
}else if(member.getMemberLevel().equals("白金会员")){
goods.setPrice(50);
}
return goods.getPrice();
}
}
package state.member;
/**
*
*/
public class Test {
public static void main(String[] args) {
Member member = new Member();
Goods goods = new Goods();
goods.setPrice(100);
Context context = new Context(member);
System.out.println(context.price(goods));
member.setMemberLevel("黄金会员");
System.out.println(context.price(goods));
member.setMemberLevel("白金会员");
System.out.println(context.price(goods));
}
}
输出
21、访问者模式(Visitor)
访问者模式把数据结构和作用于结构上的操作解耦合,使得操作集合可相对自由地演化。访问者模式适用于数据结构相对稳定算法又易变化的系统。因为访问者模式使得算法操作增加变得容易。若系统数据结构对象易于变化,经常有新的数据对象增加进来,则不适合使用访问者模式。访问者模式的优点是增加操作很容易,因为增加操作意味着增加新的访问者。访问者模式将有关行为集中到一个访问者对象中,其改变不影响系统数据结构。其缺点就是增加新的数据结构很困难。—— From 百科
简单来说,访问者模式就是一种分离对象数据结构与行为的方法,通过这种分离,可达到为一个被访问者动态添加新的操作而无需做其它的修改的效果。
来看看原码:一个Visitor类,存放要访问的对象,
package vistor;
public interface Visitor {
void visit(Subject sub);
}
package vistor;
public class Visit implements Visitor {
@Override
public void visit(Subject sub) {
System.out.println("visit the subject:"+sub.getSubject());
}
}
package vistor;
public class Visit1 implements Visitor {
@Override
public void visit(Subject sub) {
System.out.println(sub.getSubject()+"哈哈哈 这是visit1");
}
}
Subject类,accept方法,接受将要访问它的对象,getSubject()获取将要被访问的属性
package vistor;
public interface Subject {
void accept(Visitor visitor);
String getSubject();
}
package vistor;
public class MySubject implements Subject {
private String subject;
public MySubject(String subject){
this.subject = subject;
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override
public String getSubject() {
return this.subject;
}
}
测试类
package vistor;
/**
* 如果我们想为一个现有的类增加新功能,不得不考虑几个事情:
* 1、新功能会不会与现有功能出现兼容性问题?
* 2、以后会不会再需要添加?
* 3、如果类不允许修改代码怎么办?面对这些问题,最好的解决方法就是使用访问者模式,访问者模式适用于数据结构相对稳定的系统,把数据结构和算法解耦
*/
public class Test {
public static void main(String[] args) {
Subject subject = new MySubject("this is subject");
Visitor visitor = new Visit();//等于一个访问器 包装了一个算法 增加访问者 就是增加一个算法
Visitor visitor1 = new Visit1();//等于一个访问器 包装了一个算法 增加访问者 就是增加一个算法 Subject 数据结构不乱动 也可以在Vistor新
subject.accept(visitor);
subject.accept(visitor1);
}
}
visit the subject:this is subject
this is subject哈哈哈 这是visit1
22、中介者模式(Mediator)
中介者模式也是用来降低类类之间的耦合的,因为如果类类之间有依赖关系的话,不利于功能的拓展和维护,因为只要修改一个对象,其它关联的对象都得进行修改。如果使用中介者模式,只需关心和Mediator类的关系,具体类类之间的关系及调度交给Mediator就行,这有点像spring容器的作用。
User类统一接口,User1和User2分别是不同的对象,二者之间有关联,如果不采用中介者模式,则需要二者相互持有引用,这样二者的耦合度很高,为了解耦,引入了Mediator类,提供统一接口,MyMediator为其实现类,里面持有User1和User2的实例,用来实现对User1和User2的控制。这样User1和User2两个对象相互独立,他们只需要保持好和Mediator之间的关系就行,剩下的全由MyMediator类来维护!基本实现:
package mediator;
public interface Mediator {
void createMediator();
void workAll();
}
package mediator;
public class MyMediator implements Mediator {
private User user1;
private User user2;
public User getUser1() {
return user1;
}
public User getUser2() {
return user2;
}
@Override
public void createMediator() {
user1 = new User1(this);
user2 = new User2(this);
}
@Override
public void workAll() {
user1.work();
user2.work();
}
}
User
package mediator;
public abstract class User {
Mediator mediator;
public User(Mediator mediator) {
this.mediator = mediator;
}
public abstract void work();
}
package mediator;
public class User1 extends User {
public User1(Mediator mediator){
super(mediator);
}
@Override
public void work() {
System.out.println("this is user1 work");
}
}
package mediator;
public class User2 extends User {
public User2(Mediator mediator){
super(mediator);
}
@Override
public void work() {
System.out.println("this is user1 work");
}
}
测试类
package mediator;
/**
* 这样User1和User2两个对象相互独立,他们只需要保持好和Mediator之间的关系就行,剩下的全由MyMediator类来维护
*/
public class Test {
public static void main(String[] args) {
Mediator mediator = new MyMediator();
mediator.createMediator();
mediator.workAll();
User user = new User1(mediator);
User user1 = new User2(mediator);
user.work();
user1.work();
}
}
这里是解耦User1和User2
23、解释器模式(Interpreter)
解释器模式是我们暂时的最后一讲,一般主要应用在OOP开发中的编译器的开发中,所以适用面比较窄。这个模式我觉得你应该先看一下他的调用方式 所有把测试类放最前面~
package interpreter;
/**
* 解释器模式是我们暂时的最后一讲,一般主要应用在OOP开发中的编译器的开发中
* 解释器模式用来做各种各样的解释器,如正则表达式等的解释器等等
*/
public class Test {
public static void main(String[] args) {
/* Context context = new Context(2,1);
Expression expression = new Plus();
System.out.println(expression.interpret(context));
Expression expression1 = new Minis();
System.out.println(expression1.interpret(context));*/
int result = new Minis().interpret(new Context(new Plus().interpret(new Context(2,1)),8));
System.out.println(result);
}
}
Context类是一个上下文环境类,Plus和Minus分别是用来计算的实现,代码如下:
package interpreter;
public interface Expression {
public int interpret(Context context);
}
package interpreter;
public class Minis implements Expression {
@Override
public int interpret(Context context) {
return context.getNum1()-context.getNum2();
}
}
package interpreter;
public class Plus implements Expression {
@Override
public int interpret(Context context) {
return context.getNum1()+context.getNum2();
}
}
package interpreter;
public class Context {
private int num1;
private int num2;
public Context(int num1, int num2) {
this.num1 = num1;
this.num2 = num2;
}
public int getNum1() {
return num1;
}
public void setNum1(int num1) {
this.num1 = num1;
}
public int getNum2() {
return num2;
}
public void setNum2(int num2) {
this.num2 = num2;
}
}
设计模式基本就这么大概讲完了,总体感觉有点简略
此处读者可将它作为一个理论基础去学习,通过这四篇博文,先基本有个概念,虽然我讲的有些简单,但基本都能说明问题及他们的特点,如果对哪一个感兴趣,可以继续深入研究!
想要源码的可以加一下我QQ:964388652 这23个模式本人写的代码对其中一些比较熟悉的设计模式有稍微修改 但除单例模式外无太多区别 在这里本人也很开心能检查完成这几篇博客 学习 观看一下比较好的博客 我觉得也有很多收获,希望你看到我的博客时也能有这种感受~