JAVA23种设计模式(3)-行为型模式11种-1
类和对象如何交互,以及划分责任和算法
1.迭代器模式(Iterator)
一句话:提供一种方法顺序访问聚合对象中的各个对象
迭代器真正是大家最常用的模式,因为Java的Set,List都提供Iterator这个接口去遍历集合中的元素,也就是统一访问子元素的接口而不用担心集合内部是怎么实现的问题,这样就可以隐藏类内部结构,完成封装.
现在自定义一个迭代器来模仿ArrayList的迭代器
//1.自定义一个迭代器
public interface MyIterator {
public boolean hasNext();
public Object next();
}
//2.自定义一个单元
public class Sheep {
private int id;
public Sheep(int id) {
super();
this.id = id;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Override
public boolean equals(Object arg0) {
Sheep other=(Sheep) arg0;
return id==other.id;
}
}
//3.定义一个数据结构是数组
public class SheepGroupA {
private static final int LENGHTH=10;
private int number;
private Sheep[] container;
public SheepGroupA()
{
container=new Sheep[LENGHTH];
number=0;
}
//增加元素
public void addSheep(Sheep sheep) {
if(number<LENGHTH)
{
container[number]=sheep;
number++;
}
else
{
throw new RuntimeException("full of container");
}
}
public MyIterator getIterator()
{
//接口提供出去给别人操作
return new Group_A_Iterater();
}
//定义的内部类使用迭代接口将SheepGroupA的数据交了出去
private class Group_A_Iterater implements MyIterator
{
private int index;
public Group_A_Iterater()
{
index=0;
}
@Override
public boolean hasNext() {
if (index < number) {
return true;
}
return false;
}
@Override
public Object next() {
Sheep menuItem = container[index];
index++;
return menuItem;
}
}
}
//4.定义一个数据结构是链式
import java.util.ArrayList;
public class SheepGroupB {
private ArrayList<Sheep> containers;
public SheepGroupB() {
containers = new ArrayList<Sheep>();
}
// 增加元素
public void addSheep(Sheep sheep) {
containers.add(sheep);
}
public MyIterator getIterator() {
// 接口提供出去给别人操作
return new Group_B_Iterater();
}
// 定义的内部类使用迭代接口将SheepGroupA的数据交了出去
private class Group_B_Iterater implements MyIterator {
private int index;
public Group_B_Iterater() {
index = 0;
}
@Override
public boolean hasNext() {
if (index < containers.size()) {
return true;
}
return false;
}
@Override
public Object next() {
Sheep sheep = containers.get(index);
index++;
return sheep;
}
}
}
//5.定义一个类使用迭代接口
public class Work {
public void feedSheep(MyIterator iterator)
{
Sheep sheep;
while(iterator.hasNext())
{
sheep=(Sheep) iterator.next();
System.out.println("喂羊了,羊的编号是:"+sheep.getId());
}
}
}
//6.测试,有两个羊群 用的是不一样的数据结构,但是在使用类中,它只用接口操作,完全解耦
public class Main {
public static void main(String[] args) {
SheepGroupA ga=new SheepGroupA();
ga.addSheep(new Sheep(1));
ga.addSheep(new Sheep(2));
ga.addSheep(new Sheep(3));
ga.addSheep(new Sheep(4));
SheepGroupB gb=new SheepGroupB();
gb.addSheep(new Sheep(5));
gb.addSheep(new Sheep(6));
gb.addSheep(new Sheep(7));
gb.addSheep(new Sheep(8));
Work worker=new Work();
System.out.println("早上喂羊了");
worker.feedSheep(ga.getIterator());
System.out.println("下午喂羊了");
worker.feedSheep(gb.getIterator());
}
}
可以看出使用迭代器,让复杂的数据结构内部不暴露,并且统一了迭代的操作,因为内部实现类统一给其他用的接口
2.模板模式(Template)
一句话:封装一个算法步骤,并允许子类为一个或多个步骤方法提供实现.
模板模式可以为子类不改变算法结构的情况下,重新定义算法中的某些步骤.
这个模式是最常用的,比如android BaseAdpater中的getView以及getView方法就是android已经封装好的算法步骤,子类要去实现它来动态调整.还有好多比如servlet的onPost(),onGet,….下面就简单写一个例子
//1.确定好基类,确定好封装的算法
public abstract class HotDrink {
//基类封装好算法步骤,为了不让它被修改用final限定死
public final void prepareRecipe()
{
//1.第一步烧开水,所有的热饮都要这么做
boilWater();
//2.加佐料
addContent();
//3.搅拌
brew();
//4.做好的热饮倒进水杯中
pourInCup();
}
//留给子类实现
protected abstract void brew();
//留给子类实现
protected abstract void addContent();
private void boilWater()
{
System.out.println("现在开始烧水");
}
private void pourInCup() {
System.out.println("热饮倒进水杯中");
}
}
//2.基类的第1个实现类-咖啡
public class Coffee extends HotDrink {
@Override
public void brew() {
System.out.println("搅拌咖啡豆");
}
@Override
public void addContent() {
System.out.println("加入的料理是咖啡豆");
}
}
//3.基类的第二个实现类 茶
public class Tea extends HotDrink {
@Override
public void brew() {
System.out.println("努力搅拌茶叶");
}
@Override
public void addContent() {
System.out.println("加入的佐料是茶叶");
}
}
//4.测试,泡两杯茶,使用都是基类写死的算法 "prepareRecipe();"
public class Main {
public static void main(String[] args) {
System.out.println("开始泡第一杯茶");
new Coffee().prepareRecipe();
System.out.println("开始泡第二杯茶...");
new Tea().prepareRecipe();
}
}
希望大家用活抽象
3.观察者模式(Observer)
一句话:对象多对一依赖的一种设计方案,被依赖的对象为Subject,依赖的对象为Obeserver,Subject通知Observer变化.
就是定义Subject接口以及定义一个Obeserver接口,在Subject中将Obeserver存起来,在通知的时候使用Obeserver的方法接收数据
//1.定义Observer接口,
public interface Observer {
public void receiveNewsPager(NewsPaper pager);
}
//2.定义Subject接口
public interface Subject {
public void registerObserver(Observer o);
public void removeObserver(Observer o);
public void notifyObservers();
}
//3.定义传递的数据包
public class NewsPaper {
private String content;
public NewsPaper(String content) {
super();
this.content = content;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
//4.定义类1实现Observer
public class Subscribe implements Observer{
private String name;
public Subscribe(String name) {
super();
this.name = name;
}
@Override
public void receiveNewsPager(NewsPaper pager) {
System.out.println(name+"收到报纸啦,收到的内容是:"+pager.getContent() );
}
}
//5.定义Subject实现类NewsSet
import java.util.ArrayList;
public class NewsSet implements Subject {
private ArrayList<Observer> subscribers;
private NewsPaper paper;
public NewsSet()
{
subscribers=new ArrayList<Observer>();
}
@Override
public void registerObserver(Observer observer) {
subscribers.add(observer);
}
@Override
public void removeObserver(Observer observer) {
subscribers.remove(observer);
}
@Override
public void notifyObservers() {
for (Observer observer : subscribers) {
observer.receiveNewsPager(paper);
}
}
public void sendPaper(NewsPaper paper)
{
this.paper=paper;
notifyObservers();
}
}
//6.测试一下
public class Main {
public static void main(String[] args) {
NewsSet newsSet = new NewsSet();
Subscribe xiaoWang = new Subscribe("xiaoWang");
Subscribe xiaoLi = new Subscribe("xiaoLi");
Subscribe xiaoZhang = new Subscribe("xiaoZhang");
//小张,小李,小王在新闻站订阅了消息
newsSet.registerObserver(xiaoWang);
newsSet.registerObserver(xiaoLi);
newsSet.registerObserver(xiaoZhang);
//新闻站发新的报纸,订阅者小张,小李,小王都得到了消息
newsSet.sendPaper(new NewsPaper("今天互联网大会召开了"));
}
}
4.中介者模式(Mediator)
一句话:用一个中介对象来封装一系列的对象交互。
中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互
这个模式与观察者模式刚好反过来,多数量的观察者,是将自己的引用交给Subject,Subject主动发消息给观察者,而中介者是将自己的引用交给数量众多的Part,同时Part也给引用交给中介者,让Part主动给发消息给中介者,中介者发消息给目标Part执行命令
//1.首先要定义部件,部件构造函数中需要将自己的引用交给已有的中介者注册
public abstract class Part {
protected Mediator mMediator;
public String name;
public Part(Mediator mediator, String name) {
this.mMediator = mediator;
this.name = name;
mediator.register(name, this);
}
public Mediator getMediator() {
return mMediator;
}
public abstract void sendMessage(int stateChange);
}
//2.定义中介者,定义能在Part中注册和获得消息的方法
public interface Mediator {
public abstract void register(String colleagueName, Part colleague);
public abstract void getMessage(int stateChange, String colleagueName);
}
//3.定义Part实现类1-电灯
public class Light extends Part {
public Light(Mediator mediator, String name) {
super(mediator, name);
}
@Override
public void sendMessage(int stateChange) {
mMediator.getMessage(stateChange, name);
}
public void turnOn() {
System.out.println("电灯打开了..");
}
}
//4.定义Part实现类2-手机
public class Phone extends Part {
public Phone(Mediator mediator, String name) {
super(mediator, name);
}
@Override
public void sendMessage(int stateChange) {
mMediator.getMessage(stateChange, name);
}
public void getNotification0()
{
System.out.println("通知:电灯电压不足");
}
public void getNotification1()
{
System.out.println("通知:电视被打开");
}
}
//5.定义Part实现类3-TV
public class TV extends Part {
public TV(Mediator mediator, String name) {
super(mediator, name);
}
@Override
public void sendMessage(int stateChange) {
mMediator.getMessage(stateChange, name);
}
public void turnOn()
{
System.out.println("电视打开了");
}
}
//6.定义mediater实现类 - 中介者
import java.util.HashMap;
public class CenterMediator implements Mediator {
//用数据结构装Part接口
private HashMap<String, Part> mContainer;
public CenterMediator() {
mContainer = new HashMap<String, Part>();
}
@Override
public void register(String colleagueName, Part colleague) {
mContainer.put(colleagueName, colleague);
}
//!!!!在这里处理定义所有的事件,留给中介者的任务就是在这里把各种消息事件补齐
@Override
public void getMessage(int stateChange, String colleagueName) {
if (colleagueName.equals("Light")) {
switch (stateChange) {
case 0:
//电灯发过来的消息0,代表发通知 让手机出消息--电灯电压不足
Phone phone=(Phone) mContainer.get("Phone") ;
phone.getNotification0();
break;
default:
break;
}
} else if (colleagueName.equals("TV")) {
switch (stateChange) {
case 1:
//电灯发过来的消息1,代表发通知 让手机出消息--电视被打开了
Phone phone=(Phone) mContainer.get("Phone") ;
phone.getNotification1();
break;
default:
break;
}
} else if (colleagueName.equals("Phone")) {
switch (stateChange) {
case 0://手机发来得消息状态0 代表打开电视
TV tv=(TV) mContainer.get("TV") ;
tv.turnOn();
break;
case 1://手机发来得消息状态1 代表打开电灯
Light light=(Light) mContainer.get("Light") ;
light.turnOn();
break;
default:
break;
}
}
}
}
优点:
通过将对象彼此解耦,可以增加对象的复用性
通过将控制逻辑集中,可以简化系统维护
可以让对象之间所传递的消息变得简单而且大幅减少
提高系统的灵活性,使得系统易于扩展和维护
缺点:
中介者承担了较多的责任,一旦中介者出现了问题,整个系统就会受到影响
如果设计不当,中介者对象本身变得过于复杂
适用场合:
一组对象之间的通信方式比较复杂,导致相互依赖,结构混乱
一个对象引用很多其他对象并直接与这些对象通信,导致难以复用该对象
5.责任链模式(Chain)
一句话:如果有多个对象都有机会处理请求,责任链可使请求的发送者和接受者解耦,请求沿着责任链传递,直到有一个对象处理了它为止.
正如名字,这是一个圆环的线性数据结构类,正如 大象-狮子-山羊-老鼠-大象…这样的环型数据结构,每个节点负责处理一定范围的事物,不是本节点的范围内,就传递给下一位,这里给一个代码示例图
//1.定义基类的节点
public abstract class Point {
//留一个引用在基类 指向下一个节点
Point nextOne;
String name;
public Point(String name) {
super();
this.name = name;
}
//这个抽象方法留个子类实现
public abstract void liftWeight( int weight);
public void setNextPoint(Point nextOne)
{
this.nextOne=nextOne;
}
}
//2.定义第1个节点 大象
public class Elephet extends Point {
public Elephet(String name) {
super(name);
}
@Override
public void liftWeight(int weight) {
if(weight>1000)
{
System.out.println("大象:"+name+"可以举起1000以上的东西");
}
else
{
//留个下一个对象处理
nextOne.liftWeight(weight);
}
}
}
//3.定义第2个节点 老虎
public class Tiger extends Point {
public Tiger(String name) {
super(name);
}
@Override
public void liftWeight(int weight) {
if( weight<1000 && weight>500 )
{
System.out.println("老虎:"+name+"可以举起500以上.1000以下的东西");
}
else
{
//留个下一个对象处理
nextOne.liftWeight(weight);
}
}
}
//4.定义第3个节点山羊
public class Goat extends Point {
public Goat(String name) {
super(name);
}
@Override
public void liftWeight(int weight) {
if( weight<500 && weight>100 )
{
System.out.println("山羊:"+name+"可以举起100以上.500以下的东西");
}
else
{
//留个下一个对象处理
nextOne.liftWeight(weight);
}
}
}
//5.定义第4个节点老鼠
public class Mouse extends Point {
public Mouse(String name) {
super(name);
}
@Override
public void liftWeight(int weight) {
if( weight<100 )
{
System.out.println("老鼠:"+name+"可以举起100 以下的东西");
}
else
{
//留个下一个对象处理
nextOne.liftWeight(weight);
}
}
}
//6.代码测试行为
public class Main {
public static void main(String[] args) {
Point elephet = new Elephet("小长");
Point tiger = new Tiger("小黄");
Point goat = new Goat("小白");
Point mouse = new Mouse("小黑");
//责任链回环形成
elephet.setNextPoint(tiger);
tiger.setNextPoint(goat);
goat.setNextPoint(mouse);
mouse.setNextPoint(elephet);
//首先让 老鼠举起1500
mouse.liftWeight(1500);//结果给大象负责
//其次让老虎举起20
tiger.liftWeight(20);//结果果然给老鼠负责了
}
}
6.访问者模式(Visitor)
一句话:对一组对象,在不改变数据结构的前提下,增加作用于这些结构元素新的功能
适合于系统有比较稳定的数据结构,又有经常变化的功能需求,它把数据结构和作用于其上的操作解耦,使得操作集合可以相对自由地演化.
也即是在一个基类中写一个方法接收一个(访问者)接口,前提这个基类的数据结构是稳定而无变化的,接收的接口的不同实现对这个基类的数据做操作
还是代码比较清楚
//1.首先我们定义这个基类元素,这个基类的数据结构要求是稳定的,name,workYear,salary
public abstract class Element {
protected String name;
protected int workYear;
protected int salary;
private Element()
{
}
//为了数据结构保证稳定,无参数构造函数要私有掉,唯一的构造函数必须传参数
public Element(String name, int workYear, int salary) {
super();
if(name==null||workYear==0||salary==0)
{
throw new RuntimeException("name can't be null or workYear cant be 0,salary cant be 0! ");
}
this.name = name;
this.workYear = workYear;
this.salary = salary;
}
//抽象方法传入接口
abstract public void accept(Visitor visitor);
//提供方法操作数据
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getWorkYear() {
return workYear;
}
public void setWorkYear(int workYear) {
this.workYear = workYear;
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
}
//2.定义访问者,它的实现类用于操作基类的数据结构
public interface Visitor {
void visit( Element element );
}
//3.定义访问者实现类1.少量年终奖
public class LessBonusVisitor implements Visitor {
@Override
public void visit(Element element) {
String name = element.getName();
int salary = element.getSalary();
int workYear = element.getWorkYear();
System.out.println("奖励..少量年终奖,发给"+name+",合计"+(salary*0.5+workYear*50)+"元年终奖");
}
}
//4.定义访问者实现类2.中等年终奖
public class MidBonusVisitor implements Visitor {
@Override
public void visit(Element element) {
String name = element.getName();
int salary = element.getSalary();
int workYear = element.getWorkYear();
System.out.println("奖励..中等年终奖,发给"+name+",合计"+(salary*1.5+workYear*500)+"元年终奖");
}
}
//5.定义访问者实现类3.大量年终奖
public class MuchBonusVisitor implements Visitor {
@Override
public void visit(Element element) {
String name = element.getName();
int salary = element.getSalary();
int workYear = element.getWorkYear();
System.out.println("奖励..大量年终奖,发给"+name+",合计"+(salary*3+workYear*1000)+"元年终奖");
}
}
//6.定义被访问者,雇员
public class Employee extends Element{
public Employee(String name, int workYear, int salary) {
super(name, workYear, salary);
}
//这里是关键,接口进来后一定要让接口访问这个对象
@Override
public void accept(Visitor visitor) {
//!!!!!!!!!关键!!!!!!!!!!
visitor.visit(this);
}
}
//7.定义一个数据结构对一群雇员做统一管理
import java.util.HashMap;
public class Employees {
private HashMap<String, Employee> employees;
public Employees() {
employees = new HashMap<String, Employee>();
}
//增加雇员
public void Attach(Employee employee) {
employees.put(employee.getName(), employee);
}
//削减雇员
public void Detach(Employee employee) {
employees.remove(employee);
}
//得到雇员
public Employee getEmployee(String name) {
return employees.get(name);
}
//分配奖金!!这个提供一个访问者的实现类,对数据结构内的所有雇员做统一的定义好的算法处理
public void shareBonus(Visitor visitor) {
for (Employee employee : employees.values()) {
employee.accept(visitor);
}
}
}
//8.最后一步做测试
public class Main {
public static void main(String[] args) {
Employees mEmployees = new Employees();
mEmployees.Attach(new Employee("LiLei", 2, 5000));
mEmployees.Attach(new Employee("WangMeiMei", 3, 20000));
mEmployees.Attach(new Employee("MaYun", 10, 200000));
//公司今年效益下降,决定奖励少量年终奖
System.out.println("决定奖励少量年终奖");
mEmployees.shareBonus(new LessBonusVisitor());
//年末得到一个大订单,奖励中等年终奖
System.out.println("决定奖励中等年终奖");
mEmployees.shareBonus(new MidBonusVisitor());
//被土豪公司收购,奖励大量年终奖
System.out.println("决定奖励大量年终奖");
mEmployees.shareBonus(new MuchBonusVisitor());
}
}
这个模式还是比较有用的,如果发年终奖的方法定义在基类或者定义到数据结构中都需要大量改动代码,但是如果把发年终奖定义成算法族中,那么就不需要改动大量代码,实现了解耦,但是它需要前提是基类数据结构不能变动了
优点:
1.责任单一
2.拓展性良好
3.有益于系统的管理和维护
缺点:
1.增加新的元素类变得困难
2.破坏封装性
欢迎加入技术博客达人群-235496381 互相交流,这里有技术美女调戏,有开发小哥勾搭
我是”努力的人最幸运”!