设计模式第十二次作业——观察者模式、状态模式

组件协作模式:现代软件专业分工之后的第一个结果是“框架与应用程序的划分”,“组件协作”模式通过晚期绑定,来实现框架与 应用程序之间的松耦合,是二者之间协作时常用的模式。
典型模式: Strategy 、Template Method、 Observer/Event**

观察者模式——公司同事代码实现

动机:在软件构建过程中,我们需要为某些对象建立一种“通知依赖关系” 一个对象(目标对象)的状态发生改变,所有的依赖对象 (观察者对象)都将得到通知.
如果这栏的依赖关系过于紧密将使软件不能很好地抵御变化。
使用面向对象技术,可以将这种依赖关系弱化,并形成一种稳定的依赖关系。从而实现软件体系结构的松耦合。

//双向耦合的代码
import java.util.ArrayList;
public class main {
	public static void main(String[] args) {

		Secretary t = new Secretary();
		StockObserver dabao = new StockObserver("大宝", t);
		StockObserver xiaobao = new StockObserver("小宝", t);
		t.Attach(dabao);
		t.Attach(xiaobao);
		t.setAction("老板回来了");
		t.Notify();
	}
}
//前台秘书类
class Secretary {
	private ArrayList<StockObserver> observers = new ArrayList<StockObserver>();
	private String action;

	public void Attach(StockObserver observer) {// 增加
		observers.add(observer);
	}

	public void Notify() {// 通知
		for (int i = 0; i < observers.size(); i++) {
			observers.get(i).Update();
		}
	}

	public String getAction() {
		return action;
	}

	public void setAction(String action) {
		this.action = action;
	}
}

//看股票同事类——依赖Secretary
class StockObserver {
	private String name;
	private Secretary sub;// 前台

	public StockObserver(String name, Secretary sub) {
		this.name = name;
		this.sub = sub;
	}

	public void Update() {
		System.out.println(sub.getAction() + name + "关闭股票行情,继续工作!");
	}
}

前台’类增加观察者, 观察者类需要前台的状态。前台” 类和看股票者类之间互相耦合。
如果观察者中还有人想看NBA直括, 前台 类代码就需修改,因为‘前台’ 类和StockObserver都是具体类,
依赖具体使得关与类之间产生了紧密联系(耦合),以后假如出现变化,则变一次就要改一次,违背了开放-封闭原则。
解决办法:依赖倒转原则——依赖于抽象,而不是相依赖。 依赖抽象才能应对变化,避免耦合。
尤其需要注意的是, 即使“前台”类是从外部传入对象—即依赖注入,但是传入的不是抽象对象,也会产生耦合。把外部传入的对象尽 量抽象出来,不要产生耦合。
——将两个类(通与类和观察者类)抽象化,然后三相依赖抽象编程,就成功解耦

在这里插入图片描述

实现二:依赖于抽象

public class main {
	public static void main(String[] args) {
		Secretary s=new Secretary();
		StockObserver s1=new StockObserver("dada", s);
		NBAObserver s2=new NBAObserver("xixi", s);
		s.Attach(s1);
		s.Attach(s2);
		s.setAction("老板回来了");
		s.Notify();
	}
}

//抽象通知者
abstract class Subject {
	abstract void Attach(Observer observer);// 添加观察者

	abstract void Detach(Observer observer);// 删除观察者

	abstract void Notify();

	String action;

	public String getAction() {// 老板状态
		return action;
	}

	public void setAction(String action) {
		this.action = action;
	}
}

//老板类
class Boss extends Subject {
	private ArrayList<Observer> observers = new ArrayList<Observer>();

	void Attach(Observer observer) {
		observers.add(observer);
	}

	void Detach(Observer observer) {
		observers.remove(observer);
	}

	void Notify() {
		for (int i = 0; i < observers.size(); i++) {
			observers.get(i).Update();
		}
	}

}

//前台秘书类
class Secretary extends Subject {
	private ArrayList<Observer> observers = new ArrayList<Observer>();

	void Attach(Observer observer) {
		observers.add(observer);
	}

	void Detach(Observer observer) {
		observers.remove(observer);
	}

	void Notify() {
		for (int i = 0; i < observers.size(); i++) {
			observers.get(i).Update();
		}
	}

}

//抽象观察者
abstract class Observer {
	protected String name;
	protected Subject sub;// sub是抽象通知者,把与前台耦合的地方改成针对抽象的通知者

	public Observer(String name, Subject sub) {
		super();
		this.name = name;
		this.sub = sub;
	}

	public abstract void Update();
}

//看股票的同事类
class StockObserver extends Observer {
	public StockObserver(String name, Subject sub) {
		super(name, sub);
	}

	public void Update() {
		System.out.println(sub.getAction() + name + "关闭股票行情,继续工作!");

	}

}
//看NBA的同事类
class NBAObserver extends Observer {
	public NBAObserver(String name, Subject sub) {
		super(name, sub);
	}

	public void Update() {
		System.out.println(sub.getAction() + name + "关闭NBA直播,继续工作!");

	}

}

观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象.
这个主题对象在状态上发生变化时,会通知所有观察者对象,使它们能够自动更新自己。

观察者模式又叫做:
发布-订阅(Publish/Subseribe)模式
模型-视图(ModelNiew)模式
源-监听器(Source/Listener)模式
从扁者(Dependents)模式

观察者模式代码

public class main {
	public static void main(String[] args) {
		ConcreteSubject c=new ConcreteSubject();
		c.Attach(new ConcreteObserver(c, "X"));
		c.Attach(new ConcreteObserver(c, "Y"));
		c.Attach(new ConcreteObserver(c, "Z"));
		c.setSubjectState("ABC");
		c.Notify();
	}
}
/*Subject类,主题或抽象通与者,一般用一个抽象类或一个接口实现。
 * 它把所有对观察者对象的引用保存在一个聚集旦面, 每个主题都可以车
 * 任何数量的观察者。抽象主题提供 个接口, 可以增加和删除观察者对象*/
abstract class Subject{
	private ArrayList<Observer> observers = new ArrayList<Observer>();

	void Attach(Observer observer) {// 添加观察者
		observers.add(observer);
	}

	void Detach(Observer observer) {// 删除观察者
		observers.remove(observer);
	}

	void Notify() {//通知
		for (int i = 0; i < observers.size(); i++) {
			observers.get(i).update();
		}
	}
}
/*Observer类,抽象观察者, 为所有的具体观察者定义一个接口,在得到主题的通知时更新自己, 这个 接口叫做更新接口。 
 * 抽象观察者一般用一个抽象类或者一个接口 实现 。更新接口通常包含一个updateO方法,这个方法叫做更新方法。*/
abstract class Observer{
	public abstract void update();
}
/*ConcreteSubject类, 叫做具体主题或具体通如者, 将有关状态存入具体观察者对象, 在具体主题的内部状态改变时,给所有登记过的观察者发出通令。 具体主题角色通常用一个具体子类实现.*/
class ConcreteSubject extends Subject{
	private String subjectState;
	public String getSubjectState() {
		return subjectState;
	}
	public void setSubjectState(String subjectState) {
		this.subjectState=subjectState;
	}
}
/*ConcreteObserver类, 具体观察者 实现抽象观察者角色所要求的更新接口 ,以便使本身的状态与 主题的状态组协调.
 *  具体观察者角色可以保存一个指向具体主题对象的引 用, 具体观察者角色通常用一个具体子类实现。
*/
class ConcreteObserver extends Observer{
	private String name;
	private String observerState;
	private ConcreteSubject subject;
	public ConcreteObserver(ConcreteSubject subject,String name) {
		this.subject=subject;
		this.name=name;
	}
	public void update() {
		observerState=subject.getSubjectState();
		System.out.println("观察者"+name+"的新状态是:"+observerState);
	}
	
}

将一个系统分割成一系列的相互协作的类有一个副作用:
需妥维护相关对象的一致性。 不希望为了维持一致性而使种类紧密耦合,这样会给维护、扩展和重用都带来不便。
观察者模式的关键对象是主题Subject和观察者Observer,一个Subject可以有任意数目依赖它的Observer,一旦Subject的状态发生了改变,所有的Observer都可以得到通知。
Subject发出通知时并不需要知道谁是它的观察者,也就是说,具体观察者是谁,它根本不需要知道任何一个具体观察者不知道也不需要知道其他观察者的存在。
当一个对象的改变需同时改变其他对象,而且它不知道具体有多少对象有待改变时,应该考虑使用观察者模式。
当一个抽象模式有两个方面,其中一方面依赖于另一方面,这时用观察者模式可以将两者封装在独立的对象中使它们各自独立地改变和复用
观察者模式所做的二作就足解除耦合 让耦合的双方都依赖于抽象,而不是依赖于吴体。从而使得各自的变化都不会影响另一边的变化。
这是依赖倒转原则的最佳体现。
单向依赖
观察者和目标是单向依赖的,只有观察者依赖于目标,而目标不依赖子观察者。
它们之间联系的主力权掌握在目标手中,只有目标知道什么时候需要通知观察者,在整个过程中,观察者始终是被动的,被动的等待目标的通知,等待目标传给它。
对目标而言、 所有的观察者都是一样的,目标会
视同仁的对待 ,当然也可以通过在目标里面进行控制,实现有区别对待观察者,比如某些状态变化,只需要通知部分观察者,这不属于标准的、原始的观察者模式。
相互观察
在某些应用里面,可能会出现目标和观察者相三观察的情况。
如:有两套观察者模式的应用:
·· 其中一套观察者模式的实现足A对象、B对象观察C对象;在另一套观察者模式的实现足B对象、C对象观察A对象,
那么A对象和C对象就是在相互观察。
A对象的状态变化会引起C对象的联动操作,反过来,C对象的状态变化也佘引起A对象的联动操作。对于出现这种状况, 要特别小心处理, 因为可能会出现死循环的情况

观察者模式的不足:

尽管已经用了依赖倒转原则,但是 ‘抽象通知者’ 还是依赖 ‘抽象观察者’,也就是说, 万一没有了抽象观察者这样的接口,通知的功能就完成不了。
被观察者会白所有的登记过的观察者发出通知,不管观察者需不需要,每个观察者都会被调用update方法。

Java模式的观察者模式

public class main {
	public static void main(String[] args) {
		Wolf wolf =new Wolf("wolf1");
		Sheep s1=new Sheep("sheep1");
		Sheep s2=new Sheep("sheep2");
		Sheep s3=new Sheep("sheep3");
		wolf.addObserver(s1);
		wolf.addObserver(s2);
		String wolfState="hungry";
		wolf.shout(wolfState);
	}
}
//被观察者类
class Wolf extends Observable{
	private String name;
	Wolf(String name){
		this.name=name;
	}
	public void shout(String state) {
		System.out.println(this.getName()+" shouting");
		this.setChanged();
		this.notifyObservers(state);
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name=name;
	}
}
class Sheep implements Observer{
	private String state="eating";
	private String name;
	public Sheep(String name) {
		this.name=name;
	}
	public String getState() {
		return state;
	}
	public void setState(String state) {
		this.state = state;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}

	public void update(Observable o, Object arg) {
		Wolf wolf=(Wolf)o;
		System.out.println(wolf.getName()+" shouting and"+arg+" "+this.getName()+"running....");
		
	}
}

状态模式

在组件构建过程中, 某些对象的状态经常面临变化,如何对这些变化进行有效的管理?同时又维持高层模块的稳定?
状态变化”模式为这一问题提供了一种解决方案。
典型模式:
State
Memento

人、事物在不同的状态下会有不同表现(动作),而一个状态又会在不同的表现下转移到一个不同的状态(State)。
一个生活中的例子:地铁入口处,如果放入正萌的地铁票,门就会打开通过。在出口处也是验票, 如畏正确就可以OK,否则就不让通过。
有限状态自动机(FSM)也是一个共型的例子: 状态不同,对输入有不同的响应(状态转移)。

实现这类系统通常会使用到很多的switch-case语句或者if-else语句,case某种状态,发生某种动作,case另外一种状态,则发生另外一种动作。
但是这种实现方式至少有以下两个问题:
当状态数目不是很多的时候,switch-case可以搞定。
但是当状态数日很多的时候,维护一大组的switch-case语句将异常困难并容易出错。
状态逻辑和动作实现没有分离 ——紧耦合。在很多的系统实现中,动作的实现代码直接写在状态的逻辑当中。
这带来的后果就是系统的扩展性和可维护性得不到保证。

状态模式——工作状态的变化代码实现

public class main {
	public static void main(String[] args) {
		Work e=new Work();
		e.setHour(9);
		e.WriteProgram();
		e.setHour(10);
		e.WriteProgram();
		e.setHour(12);
		e.WriteProgram();
		e.setHour(13);
		e.WriteProgram();
		e.setHour(14);
		e.WriteProgram();
		e.setHour(17);
		e.WriteProgram();
		e.setFinish(false);
		e.setHour(19);
		e.WriteProgram();
		e.setHour(22);
		e.WriteProgram();
	}
}
class Work{
	private int hour;
	private Boolean finish=false;
	public int getHour() {
		return hour;
	}
	public void setHour(int hour) {
		this.hour = hour;
	}
	public Boolean getFinish() {
		return finish;
	}
	public void setFinish(Boolean finish) {
		this.finish = finish;
	}
	public void WriteProgram() {
		if(hour<12) {
			System.out.println("当前时间:"+hour+"点 上午工作,精神百倍");
		}else if(hour<13) {
			System.out.println("当前时间:"+hour+"点 饿了,午饭;犯困,午休");
		}else if(hour<17) {
			System.out.println("当前时间:"+hour+"点 下午状态还不错,继续努力");
		}else {
			if(finish) {
				System.out.println("当前时间:"+hour+"点 下班回家了");
			}else {
				if(hour<21) {
					System.out.println("当前时间:"+hour+"点 加班,疲累之极");
				}else {
					System.out.println("当前时间:"+hour+"点 不行了,睡觉");
				}
			}
		}
	}
}

状态模式的缺点:

Work类的writeProgram方法旦的判断过多,导致方法过长。
方法很长,而里有很多个判断分支, 意味着它的责任过大,面向对象设计其实就是希望做到代码的责任分解。——违背了 “单一职责原则”
writeProgram的方法旦有很多判断,使得任何需求的改动或增加都需妥去更改这个方法, 但目前的代码却是对整个方法做改动的,维护出错的风险很大。 违背了“开放-封闭原则。

状态模式(State):

当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了它的类。
状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类当中,可以把复杂的逻辑简化。
State模式分–状态逻辑和动作实现如昊这个状态判断很简单, 那就没必耍用‘状态模式’。

在这里插入图片描述

状态模式代码

public class main {
	public static void main(String[] args) {
		Context c=new Context(new ConcreteStateA());
		c.Request();
		c.Request();
		c.Request();
		c.Request();
	}
}
//State类,抽象状态类,定义一个接口或抽象类,一封装与Context的一个特定状态相关的行为
abstract class State{
	public abstract void Handle(Context context);
}
//ConcreteState类,具体状态,每一个子类实现一个与Context的一个状态相关的行为。
class ConcreteStateA extends State{

	public void Handle(Context context) {
		context.setState(new ConcreteStateB());
		
	}
	
}
class ConcreteStateB extends State{

	public void Handle(Context context) {
		context.setState(new ConcreteStateA());
		
	}
	
}
class Context{
	private State state;

	public Context(State state) {
		super();
		this.state = state;
	}

	public State getState() {
		return state;
	}

	public void setState(State state) {
		this.state = state;
		System.out.println("当前状态:"+state.toString());
	}
	public void Request() {
		state.Handle(this);
	}
	
}

实现二

public class main {
	public static void main(String[] args) {
		Work w=new Work();
		w.setHour(9);
		w.WriteProgrom();
		w.setHour(10);
		w.WriteProgrom();
		w.setHour(12);
		w.WriteProgrom();
		w.setHour(13);
		w.WriteProgrom();
		w.setHour(14);
		w.WriteProgrom();
		w.setHour(17);
		w.WriteProgrom();
		w.setFinish(false);
		w.setHour(19);
		w.WriteProgrom();
		w.setHour(22);
		w.WriteProgrom();
	}
}

//State类,抽象状态类,定义一个抽象方法“写程序”
abstract class State {
	public abstract void WriteProgram(Work w);
}

//工作类
class Work {
	private State current;
	private double hour;
	private boolean finish = false;

	public Work() {
		current = new ForenoonState();
	}

	public State getCurrent() {
		return current;
	}

	public void Setstate(State current) {
		this.current = current;
	}

	public double getHour() {
		return hour;
	}

	public void setHour(double hour) {
		this.hour = hour;
	}

	public boolean isFinish() {
		return finish;
	}

	public void setFinish(boolean finish) {
		this.finish = finish;
	}

	public void WriteProgrom() {
		current.WriteProgram(this);
	}
}

//上午工作类
class ForenoonState extends State {

	public void WriteProgram(Work w) {
		if (w.getHour() < 12) {
			System.out.println("当前时间:" + w.getHour() + "点 上午工作,精神百倍");
		} else {
			w.Setstate(new NoonState());
			w.WriteProgrom();
		}

	}

}

//中午工作类
class NoonState extends State {

	public void WriteProgram(Work w) {
		if (w.getHour() < 13) {
			System.out.println("当前时间:" + w.getHour() + "点 饿了,午饭;犯困,午休");
		} else {
			w.Setstate(new EveningState());
			w.WriteProgrom();
		}

	}

}

//晚上工作状态
class EveningState extends State {

	public void WriteProgram(Work w) {
		if (w.isFinish()) {

		} else if (w.getHour() < 21) {
			System.out.println("当前时间:" + w.getHour() + "点 加班,疲累之极");
		} else {
			w.Setstate(new SleepingState());
			w.WriteProgrom();
		}

	}

}

//睡眠状态
class SleepingState extends State {

	public void WriteProgram(Work w) {

		System.out.println("当前时间:" + w.getHour() + "点 不行了,睡觉");

	}

}

//下班休息类
class RestState extends State {

	public void WriteProgram(Work w) {

		System.out.println("当前时间:" + w.getHour() + "点 下班,回家了");

	}

}

状态模式的优点 :

将与特定状态相关的行为局部化, 并且将不同状态的行为分割开来,将特定的状态相关的行为都放入一个对象中,由于所有与状态相关的代码都存在于 某个ConcreteState中,所以通过定义新的子类可以容易地增加新的状态和转换。
消除庞大的条件分支话句,扎各种状态转移逻辑分布到State的子类之间,减少了相三间的依赖。
显式进行状态转换:为不同的状态引入独立的对象,使得状态的转换变得更加明确。而三状态对率可以保证上下文不会发生内部状态不一致的状况,因为上下文中只有一个变量来记录状态对象,只要为这一个变量赋佳就可以了。

什么时候使用状态模式?

当一个对象的行为取决于它的状态,并且它必须在运行时根据状态改变行为时,就可以考虑使用状态模式。
另外如是业务需求某项业务有多个状态,通常都是一些枚举常量,状态的变化都是依靠大量的多分支判断语句来实现,比如应该考虑每一种业务状态定义为一个State的子类。这样这些对象就可以不依赖于其他对象而独立变化了,如果需要更改需求,增加或减少业务状态或改变状态流程,都不困难了。

State模式和Strategy模式简单比较

State模式和Strategy模式有很大程度的相似:它们都有一个Context类,都是通过组合/聚合给一个具有多个派
生类的多态基类实现Context的算法逻辑。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Sweet y y y y u

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值