Java设计模式——行为型
本章接着讨论行为型的设计模式。
12、策略模式
策略模式定义了一系列算法,并将每个算法封装起来,使他们可以相互替换,且算法的变化不会影响到使用算法的客户。
——使用情景:
- 程序不希望暴露复杂的、与算法有关的数据结构,那么可以使用策略模式封装算法
- 需要使用一个算法的不同变体
——使用实例:
- Comparator的compare()方法
统一接口:
public interface ICalculator {
public int calculate(String exp);
}
辅助类:
public abstract class AbstractCalculator {
public int[] split(String exp,String opt){
String array[] = exp.split(opt);
int arrayInt[] = new int[2];
arrayInt[0] = Integer.parseInt(array[0]);
arrayInt[1] = Integer.parseInt(array[1]);
return arrayInt;
}
}
两个实现类:
public class Plus extends AbstractCalculator implements ICalculator {
@Override
public int calculate(String exp) {
int arrayInt[] = split(exp,"\\+");
return arrayInt[0]+arrayInt[1];
}
}
public class Minus extends AbstractCalculator implements ICalculator {
@Override
public int calculate(String exp) {
int arrayInt[] = split(exp,"-");
return arrayInt[0]-arrayInt[1];
}
}
测试类:
public class StrategyTest {
public static void main(String[] args) {
String exp = "2+8";
ICalculator cal = new Plus();
int result = cal.calculate(exp);
System.out.println(result);
}
}
13、模板方法模式
定义一个算法骨架,而将一些步骤延迟到子类中,模板方法可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
即算法骨架在超类实现,实现的细节在子类实现。
——使用情景:
- 设计者需要给出一个算法的固定步骤,并将某些步骤的具体实现留给子类来实现
- 需要对代码进行重构,将各个子类公共行为提取出来集中到一个共同的父类中以避免代码重复
——使用实例:
- java.io.InputStream, java.io.OutputStream, java.io.Reader和java.io.Writer的所有非抽象方法
- javax.servlet.http.HttpServlet#doXXX()
public abstract class Template {
public abstract void method1();
public abstract void method2();
public void operator(){
method1();
method2();
}
}
public class ConcreteA extends Template{
@Override
public void method1() {
System.out.println("A_method1");
}
@Override
public void method2() {
System.out.println("A_method2");
}
}
public class ConcreteB extends Template{
@Override
public void method1() {
System.out.println("B_method1");
}
@Override
public void method2() {
System.out.println("B_method2");
}
}
public class TemplateTest {
public static void main(String[] args) {
Template t=new ConcreteA();
t.operator();
}
}
14、观察者模式
当对象间存在一对多关系时,当一个对象的状态发生变化时,所有依赖它的对象都得到通知并自动更新。
——使用情景:
- 当一个对象的数据更新时需要通知其他对象,但这个对象又不希望和被通知的那些对象形成紧耦合
- 当一个对象的数据更新时,这个对象需要让其他对象也各自更新自己的数据,但这个对象不知道具体有多少对象需要更新数据
public interface Observer {
public void update(String s);
}
具体观察者
public class ConcreteObserver implements Observer{
private String name;
public ConcreteObserver(String name) {
this.name=name;
}
@Override
public void update(String s) {
System.out.println(name+"收到消息:"+s);
}
}
主题接口
public interface Subject {
public void attach(Observer o);
public void detach(Observer o);
public void notifyObservers(String s);
}
具体主题
public class ConcreteSubject implements Subject{
private String mess="";
private ArrayList<Observer> list=new ArrayList<>();
@Override
public void attach(Observer o) {
if(!(list.contains(o)))
list.add(o);
}
@Override
public void detach(Observer o) {
if(list.contains(o))
list.remove(o);
}
@Override
public void notifyObservers(String s) {
if(s.equals(mess))
return;
else
mess=s;
for(int i=0;i<list.size();i++){
Observer o=list.get(i);
o.update(mess);
}
}
}
public class ObserverTest {
public static void main(String[] args) {
Subject subject=new ConcreteSubject();
Observer o1=new ConcreteObserver("hjy");
Observer o2=new ConcreteObserver("Limei");
subject.attach(o1);
subject.attach(o2);
subject.notifyObservers("今天上课取消!");
}
}
15、迭代器模式
迭代器模式,提供一种方法顺序访问一个聚合对象中的各种元素,而又不暴露该对象的内部表示。
——使用情景:
- 访问一个聚合对象的内容而无需暴露它的内部表示
- 希望对遍历不同的集合提供一个统一的接口
——使用实例:
- java.util.Iterator
集合接口
public interface List {
public void add(Object obj);
public Object get(int index);
public int size();
public Iterator iterator();
}
具体集合类
public class ConcreteList implements List{
private Object[] list;
private int size=0;
private int index=0;
public ConcreteList() {
list=new Object[10];
}
@Override
public void add(Object obj) {
list[index++]=obj;
size++;
}
@Override
public Object get(int index) {
return list[index];
}
@Override
public int size() {
return size;
}
@Override
public Iterator iterator() {
return new ConcreteIterator(this);
}
}
迭代器接口
public interface Iterator {
public boolean hasNext();
public Object next();
}
具体迭代器类
public class ConcreteIterator implements Iterator{
private List list;
private int index=0;
public ConcreteIterator(List list) {
this.list=list;
}
@Override
public boolean hasNext() {
return index < list.size();
}
@Override
public Object next() {
Object o=list.get(index);
index++;
return o;
}
}
public class IteratorTest {
public static void main(String[] args) {
List list=new ConcreteList();
list.add(2);
list.add(65);
list.add(23);
Iterator iterator= list.iterator();
while(iterator.hasNext())
System.out.println(iterator.next());
}
}
16、责任链模式
责任链模式,有多个对象,每个对象持有对下一个对象的引用,这样就会形成一条链,请求在这条链上传递,直到某一对象决定处理该请求。从而避免请求的发送者和接收者之间解耦。
——使用情景:
- 有多个对象可以处理用户的请求,希望程序在运行期间自动确定处理用户的那个对象
- 希望用户不必明确指定接收者的情况下,向多个接收者的一个提交请求
——使用实例:
- Java异常抛出
- web过滤链
接收者抽象类
public abstract class Handler {
protected Handler handler;
public void setHandler(Handler handler){
this.handler=handler;
}
public abstract void operator(int num);
}
3个具体接收者
public class A_handler extends Handler{
private String name;
public A_handler(String name) {
this.name=name;
}
@Override
public void operator(int num) {
if(num<10)
System.out.println(name+"处理该请求");
else
handler.operator(num);
}
}
public class B_handler extends Handler{
private String name;
public B_handler(String name) {
this.name=name;
}
@Override
public void operator(int num) {
if(num>=10 && num<20)
System.out.println(name+"处理该请求");
else
handler.operator(num);
}
}
public class C_handler extends Handler{
private String name;
public C_handler(String name) {
this.name=name;
}
@Override
public void operator(int num) {
if(num>=20 && num<30)
System.out.println(name+"处理该请求");
else
System.out.println("没人处理该请求");
}
}
请求用户类
public class Customer {
private Handler handler;
public void setHandler(Handler handler){
this.handler=handler;
}
public void operater(int num){
handler.operator(num);
}
public static void main(String[] args) {
Handler a_handler=new A_handler("A");
Handler b_handler=new B_handler("B");
Handler c_handler=new C_handler("C");
b_handler.setHandler(c_handler);
a_handler.setHandler(b_handler);
Customer customer=new Customer();
customer.setHandler(a_handler);
customer.operater(24);
}
}
17、命令模式
命令模式将一个命令封装成一个对象,达到命令的请求者和接收者之间解耦,实现请求和执行分开。
——使用情景:
- 程序需要在不同的时刻指定、排列和执行请求
- 程序需要提供撤销命令操作
——使用实例:
- Struts1就是一种将请求和呈现分离的技术,它的控制器 ActionServlet 只有一个,相当于 Invoker(请求者),而模型层的类会随着不同的应用有不同的模型类,相当于具体的命令
接收者
public class Receiver{
private String name;
public Receiver(String name) {
this.name=name;
}
public void action(String order){
System.out.println(name+"收到命令:"+order);
}
}
命令接口
public interface Order {
public void execute(String order);
}
命令实现类
public class ConcreteOrder implements Order{
private Receiver receiver;
public ConcreteOrder(Receiver receiver) {
this.receiver=receiver;
}
@Override
public void execute(String order) {
receiver.action(order);
}
}
请求者
public class Invoker {
private Order order;
public Invoker(Order order) {
this.order=order;
}
public void action(String str){
order.execute(str);
}
}
public class OrderTest {
public static void main(String[] args) {
Receiver receiver=new Receiver("hjy");
Order order=new ConcreteOrder(receiver);
Invoker invoker=new Invoker(order);
invoker.action("消灭敌人!");
}
}
18、备忘录模式
备忘录模式主要目的是保存一个对象的某个状态,以便在适当的时候恢复对象。
——使用情景:
- 需要保存/恢复数据的相关状态场景
- 提供一个可回滚的操作
——使用实例:
- 数据库事务管理
public class Original {
private String val;
public Original(String val) {
this.val=val;
}
public String getVal() {
return val;
}
public void setVal(String val) {
this.val = val;
}
public Memento createMemento(){
return new Memento(val);
}
public void restoreMemento(Memento memento){
val = memento.getVal();
}
}
public class Memento {
private String val;
public Memento(String val) {
this.val=val;
}
public String getVal(){
return val;
}
}
public class MementoTest {
public static void main(String[] args) {
Original original=new Original("hjy");
Memento memento= original.createMemento();// 创建备忘录
System.out.println("初始化状态为:" + original.getVal());
original.setVal("haha");
System.out.println("修改后的状态为:" + original.getVal());
original.restoreMemento(memento);
System.out.println("恢复后的状态为:" +original.getVal());
}
}
19、状态模式
状态模式核心思想就是:
当对象的状态改变时,同时改变其行为。状态模式在日常开发中用的挺多的,尤其是做网站的时候,我们有时希望根据对象的某一属性,区别开他们的一些功能,比如说简单的权限控制等。
——使用情景:
- 一个对象的行为依赖于它的状态,并可在运行时根据状态改变它的行为
- 当需要大量分支语句来决定一个操作的行为,而且这些条件恰好表示对象的一种状态
public class State {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public void method1(){
System.out.println("execute the first opt!");
}
public void method2(){
System.out.println("execute the second opt!");
}
}
切换类
public class Context {
private State state;
public Context(State state) {
this.state = state;
}
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
}
public void method() {
if (state.getValue().equals("state1"))
state.method1();
else if (state.getValue().equals("state2"))
state.method2();
}
}
public class StateTest {
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();
}
}
20、访问者模式
访问者模式目的是
要把处理操作从数据结构分离出来。它表示一个作用于某对象结构中的各元素的操作,它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
——使用情景:
- 对象结构中对象对应的类很少改变,但经常需要在此对象结构上定义新的操作
- 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作"污染"这些对象的类,也不希望在增加新操作时修改这些类
一个Visitor类,存放要访问的对象
public interface Visitor {
public void visit(Subject sub);
}
public class MyVisitor implements Visitor {
@Override
public void visit(Subject sub) {
System.out.println("visit the subject:"+sub.getSubject());
}
}
Subject类,accept方法,接受将要访问它的对象
public interface Subject {
public void accept(Visitor visitor);
public String getSubject();
}
public class MySubject implements Subject {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override
public String getSubject() {
return "love";
}
}
public class Test {
public static void main(String[] args) {
Visitor visitor = new MyVisitor();
Subject sub = new MySubject();
sub.accept(visitor);
}
}
21、中介者模式
用一个中介对象来封装一系列的对象交互,中介者使各对象之间完全解耦,而且可以独立地改变它们之间的交互。
——使用情景:
- 许多对象相互依赖,导致系统难以理解和维护
- 一个对象引用其他很多对象,导致难以复用该对象
——使用实例:
- MVC 框架,其中C(控制器)就是 M(模型)和 V(视图)的中介者
public interface Mediator {
public void createMediator();
public void wordAll();
}
public class ConcreteMediator implements Mediator{
private User1 user1;
private User2 user2;
@Override
public void createMediator() {
user1=new User1(this);
user2=new User2(this);
}
@Override
public void wordAll() {
user1.work();
user2.work();
}
}
public abstract class User {
private Mediator mediator;
public User(Mediator mediator) {
this.mediator=mediator;
}
public abstract void work();
}
public class User1 extends User{
public User1(Mediator mediator) {
super(mediator);
}
@Override
public void work() {
System.out.println("user1 execute!");
}
}
public class User2 extends User{
public User2(Mediator mediator) {
super(mediator);
}
@Override
public void work() {
System.out.println("user2 execute!");
}
}
public class MediatorTest {
public static void main(String[] args) {
Mediator mediator= new ConcreteMediator();
mediator.createMediator();
mediator.wordAll();
}
}