`
okhaoba
  • 浏览: 5793 次
  • 性别: Icon_minigender_1
  • 来自: 西安
社区版块
存档分类
最新评论

收藏一段经典的观察者访问者模式的代码

阅读更多
/*******************************************************************
 * This class replaces the Multicaster class that's described in
 * <i>Taming Java Threads</i>. It's better in almost every way
 * (It's smaller, simpler, faster, etc.). The primary difference
 * between this class and the original is that I've based
 * it on a linked-list, and I've used a Strategy object to
 * define how to notify listeners, thereby makeing the interface
 * much more flexible.
 * <p>
 * The <code>Publisher</code> class provides an efficient thread-safe means of
 * notifying listeners of an event. The list of listeners can be
 * modified while notifications are in progress, but all listeners
 * that are registered at the time the event occurs are notified (and
 * only those listeners are notified). The ideas in this class are taken
 * from the Java's AWTEventMulticaster class, but I use an (iterative)
 * linked-list structure rather than a (recursive) tree-based structure
 * for my implementation.
 * <p>
 * Here's an example of how you might use a <code>Publisher</code>:
 * <PRE>
 *	class EventGenerator
 *	{	interface Listener
 *		{	notify( String why );
 *		}
 *
 *		private Publisher publisher = new Publisher();
 *
 *		public void addEventListener( Listener l )
 *		{	publisher.subscribe(l);
 *		}
 *
 *		public void removeEventListener ( Listener l )
 *		{	publisher.cancelSubscription(l);
 *		}
 *
 *		public void someEventHasHappend(final String reason)
 *		{	publisher.publish
 *			(	
 *				// Pass the publisher a Distributor that knows
 *				// how to notify EventGenerator listeners. The
 *				// Distributor's deliverTo method is called
 *				// multiple times, and is passed each listener
 *				// in turn.
 *
 *				new Publisher.Distributor()
 *				{	public void deliverTo( Object subscriber )
 *					{	((Listener)subscriber).notify(reason);
 *					}
 *				}
 *			);
 *		}
 *	}
 * </PRE>
 * Since you're specifying what a notification looks like
 * by defining a Listener interface, and then also defining
 * the message passing symantics (inside the Distributor implementation),
 * you have complete control over what the notification interface looks like.
 *
 * @include /etc/license.txt
 */

public class Publisher
{
	public interface Distributor
	{	void deliverTo( Object subscriber );	// the Visitor pattern's
	}											// "visit" method.

	// The Node class is immutable. Once it's created, it can't
	// be modified. Immutable classes have the property that, in
	// a multithreaded system, access to the does not have to be
	// synchronized, because they're read only.
	//
	// This particular class is really a struct so I'm allowing direct
	// access to the fields. Since it's private, I can play
	// fast and loose with the encapsulation without significantly
	// impacting the maintainability of the code.

	private class Node
	{	public final Object subscriber;
		public final Node	next;

		private Node( Object subscriber, Node next )
		{	this.subscriber	= subscriber;
			this.next		= next;
		}

		public Node remove( Object target )
		{	if( target == subscriber )
				return next;

			if( next == null ) 						// target is not in list
				throw new java.util.NoSuchElementException
												(target.toString());

			return new Node(subscriber, next.remove(target));
		}

		public void accept( Distributor deliveryAgent ) // deliveryAgent is
		{	deliveryAgent.deliverTo( subscriber );		 // a "visitor"
		}
	}

	private volatile Node subscribers = null;

	/** Publish an event using the deliveryAgent. Note that this
	 *  method isn't synchronized (and doesn't have to be). Those
	 *  subscribers that are on the list at the time the publish
	 *  operation is initiated will be notified. (So, in theory,
	 *  it's possible for an object that cancels its subsciption
	 *  to nonetheless be notified.) There's no universally "good"
	 *  solution to this problem.
	 */

	public void publish( Distributor deliveryAgent )
	{	for(Node cursor = subscribers; cursor != null; cursor = cursor.next)
			cursor.accept( deliveryAgent );
	}

	synchronized public void subscribe( Object subscriber )
	{	subscribers = new Node( subscriber, subscribers );
	}

	synchronized public void cancelSubscription( Object subscriber )
	{	subscribers = subscribers.remove( subscriber );
	}

	//------------------------------------------------------------------
	private static class Test
	{
		static final StringBuffer actualResults   = new StringBuffer();
		static final StringBuffer expectedResults = new StringBuffer();

		interface Observer
		{	void notify( String arg );
		}

		static class Notifier
		{	private Publisher publisher = new Publisher();

			public void addObserver( Observer l )
			{	publisher.subscribe(l);
			}

			public void removeObserver ( Observer l )
			{	publisher.cancelSubscription(l);
			}

			public void fire( final String arg )
			{	publisher.publish
				(	new Publisher.Distributor()
					{	public void deliverTo( Object subscriber )
						{	((Observer)subscriber).notify(arg);
						}
					}
				);
			}
		}

		public static void main( String[] args )
		{
			Notifier source = new Notifier();
			int      errors = 0;

			Observer listener1 =
				new Observer()
				{	public void notify( String arg )
					{	actualResults.append( "1[" + arg + "]" );
					}
				};

			Observer listener2 =
				new Observer()
				{	public void notify( String arg )
					{	actualResults.append( "2[" + arg + "]" );
					}
				};

			source.addObserver( listener1 );
			source.addObserver( listener2 );

			source.fire("a");
			source.fire("b");

			expectedResults.append("2[a]");
			expectedResults.append("1[a]");
			expectedResults.append("2[b]");
			expectedResults.append("1[b]");

			source.removeObserver( listener1 );

			try
			{	source.removeObserver(listener1);
				System.err.print("Removed nonexistant node!");
				++errors;
			}
			catch( java.util.NoSuchElementException e )
			{	// should throw an exception, which we'll catch
				// (and ignore) here.
			}

			expectedResults.append("2[c]");
			source.fire("c");

			if( !expectedResults.toString().equals(actualResults.toString()) )
			{
				System.err.print("add/remove/fire failure.\n");
				System.err.print("Expected:[");
				System.err.print( expectedResults.toString() );
				System.err.print("]\nActual:  [");
				System.err.print( actualResults.toString() );
				System.err.print("]");
				++errors;
			}

			source.removeObserver( listener2 );
			source.fire("Hello World");
			try
			{	source.removeObserver( listener2 );
				System.err.println("Undetected illegal removal.");
				++errors;
			}
			catch( Exception e ) { /*everything's okay, do nothing*/ }

			if( errors == 0 )
				System.err.println("com.holub.tools.Publisher: OKAY");
			System.exit( errors );
		}
	}
}

 

 

 

Node 的设计考虑比较细致,订阅者不会接收到订阅前发布的主题。

 

 

 

分享到:
评论

相关推荐

    举例讲解Python设计模式编程中的访问者与观察者模式

    这段代码展示了如何使用访问者模式来遍历一个由多个元素组成的复杂对象,并根据不同类型的元素执行不同的操作。通过这种方式,可以在不修改现有元素类的情况下轻松地扩展系统的行为。 #### 观察者模式解析 观察者...

    java设计模式-图解-附代码

    例如,责任链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、模板方法和访问者模式。这些模式帮助我们设计出更加灵活、可扩展和可维护的系统,比如观察者模式...

    大话模式源代码示例

    以上只是设计模式中的一部分,"大话模式源代码示例"涵盖的28个实例将覆盖更多的模式,如命令模式、职责链模式、状态模式、访问者模式等。通过这些源代码,我们可以深入理解每个模式的工作原理,学习如何在实际项目中...

    极客《设计模式之美》课程的相关代码实现及课后作业.zip

    例如,可能会有一个任务是使用设计模式重构一段复杂代码,或者设计一个满足特定需求的系统架构。通过完成这些作业,学习者不仅能够掌握设计模式的理论,还能提升实际编程技能。 总之,《设计模式之美》课程的代码...

    经典23个设计模式【转】

    C#中的访问者模式通常用于代码分析和修改。 18. **备忘录模式**:在不破坏封装性的前提下,捕获一个对象的状态,并在该对象状态改变时恢复。C#中的序列化和反序列化可以实现备忘录。 19. **状态模式**:允许对象在...

    Java设计模式面试题汇总

    包括责任链模式、命名模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、模板模式、访问者模式等。 常见设计模式: 工厂模式:工厂模式指由一个工厂对象来创建实例,客户端...

    C#设计模式作业1、3.rar

    观察者模式是一种行为设计模式,它定义了对象之间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。在C#中,System.ComponentModel命名空间下的INotifyPropertyChanged...

    C#设计模式PDF 电子书

    观察者模式定义了对象间的一种一对多依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并被自动更新。C#中的事件和委托机制就是观察者模式的实现。 七、策略模式(Strategy) 策略模式定义了...

    iOS开发中的几种设计模式介绍

    此外,Key-Value Observing (KVO)也是一种观察者模式的应用,它允许对象监听其他对象属性的变化。这种模式遵循接口隔离原则,让发布者只负责发布,不关心谁接收。 3. **MVC模式**: Model-View-Controller模式是...

    设计模式与重构(design pattern )

    如策略模式(Strategy)、模板方法模式(Template Method)、观察者模式(Observer)、迭代器模式(Iterator)、命令模式(Command)、责任链...状态模式(State)、访问者模式(Visitor)和解释器模式(Interpreter)...

    深入浅出设计模式(英文扫描版)

    如策略模式、模板方法模式、观察者模式、命令模式、迭代器模式、解释器模式、中介者模式、备忘录模式、状态模式、策略模式和访问者模式。 ### 英文学习与专业技能并重 《深入浅出设计模式(英文扫描版)》这本书除了...

    图说设计模式 Graphic Design Patterns

    行为型模式关注对象间的通信,比如责任链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、模板方法模式和访问者模式等。 每一种设计模式都有其特定的用途和优...

    软件架构设计代码

    在实际编码过程中,架构设计代码会体现这些模式和原则,比如使用设计模式如工厂模式、策略模式、观察者模式等,以实现灵活和可扩展的系统。同时,为了保证代码质量,还需要遵循编程规范,如命名规范、注释规范、错误...

    java设计模式+算法

    书中可能涵盖了23种经典设计模式,如工厂模式、建造者模式、原型模式、适配器模式、装饰模式、桥接模式、组合模式、享元模式、外观模式、代理模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察...

    从追MM浅谈Java的23种设计模式

    - 访问者模式:表示一个作用于某对象结构中的各元素的操作,它使你可以在不改变元素的类的前提下定义作用于这些元素的新操作。 追MM的过程可以巧妙地与设计模式联系起来。比如,单例模式就像是追求MM时的独特策略...

    设计模式.pdf_学习模式必备

    - **Visitor**:访问者模式,表示一个作用于某对象结构中的各元素的操作。 ### 多执行绪模式 在多线程环境中,确保数据的一致性和程序的正确性非常重要,因此多线程模式对于处理并发问题尤为重要。 - **Guarded ...

    设计模式实现

    例如,观察者模式定义了对象之间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新;责任链模式将请求沿着处理者链传递,直到有处理者处理请求;策略模式定义了一系列算法,...

    C#设计模式随书源码

    如责任链模式(Chain of Responsibility)、命令模式(Command)、解释器模式(Interpreter)、迭代器模式(Iterator)、备忘录模式(Memento)、...Strategy)、模板方法模式(Template Method)和访问者模式(Visitor)...

    软件工程 设计模式PDF 福州大学

    如策略模式(Strategy)、模板方法模式(Template Method)、观察者模式(Observer)、迭代器模式(Iterator)、命令模式(Command)、责任链...状态模式(State)、访问者模式(Visitor)和解释器模式(Interpreter)...

Global site tag (gtag.js) - Google Analytics