C# 设计模式——责任链模式

学习链接:

行为型模式之责任链模式 - 二次元攻城狮 - 博客园 (cnblogs.com)

正文

首先,我们要搞清楚责任链模式的结构及其目的。

结构很简单,责任链模式下,事件的处理分为事件发起者和事件处理者,事件处理者是多个处理者的集合,此集合的节点之间成链式关系(节点与节点之间相连)。责任链模式的用于在于讲事件发起者和处理者以及处理逻辑高度解耦,按照以往的逻辑,事件发起者独自处理事件的时候,如果需要写一个统一的数据接口,就需要撰写大量的if else进行数据类型判断然后根据数据类型来处理。

很明显,大量的if else就是设计模式的处理对象之一。

下面是一段简单的C# 责任链模式代码。


    public enum HandlerType
{
	floatHandler,stringHandler
}
#region 抽象基类
//抽象基类
public abstract class Handler
{
	private Handler next;
	public void SetNext(Handler next)
	{
		this.next = next;
	}
	public virtual void Set(HandlerType handlerType,ref HandlerStruct value)
	{
		if(GetHandlerType() == handlerType)
		{
			HandlerRequest(ref value);
		}
		else
		{
			next.Set(handlerType,ref value);
		}
	}
	protected abstract void HandlerRequest(ref HandlerStruct value);
	public abstract HandlerType GetHandlerType();	
}
#endregion
public struct HandlerStruct
{
	Object objValue;
	Type type;
	
	public HandlerStruct(Type type,object objValue)
	{
		this.objValue = objValue;
		this.type = type;
	}
	public T? GetValue<T>() where T : class
	{
		if(objValue is null || type is null || typeof(T) != type)
		{
			return null;
		}
		return objValue as T;
	}
}
#region 具体处理类
//具体处理类
public class FloatHandler : Handler
{
	protected override void HandlerRequest(ref HandlerStruct value)
	{
		Console.WriteLine($"floatHandler:{value.GetValue<FloatModel>()}");
	}
	public override HandlerType GetHandlerType()
	{
		return HandlerType.floatHandler;
	}

	public class FloatModel
	{
		public float value;

		public FloatModel(float value)
		{
			this.value = value;
		}
		public override string ToString()
		{
			return value.ToString();
		}
	}
}
public class StringHandler : Handler
{
	protected override void HandlerRequest(ref HandlerStruct value)
	{
		Console.WriteLine($"stringHandler{value.GetValue<string>()}");
	}
	public override HandlerType GetHandlerType()
	{
		return HandlerType.stringHandler;
	}	
}
#endregion

//处理中心
public static class HandlerCenter
{
	private static List<Handler> mHandlers = new List<Handler>();
	static HandlerCenter()
	{
	    mHandlers.Add(new FloatHandler());
		mHandlers.Add(new StringHandler());
	}
	private static void Init()
	{
		if(mHandlers.Count < 2)
		{
			return;
		}
		//单链式责任链
		for(int i = 0 ; i < mHandlers.Count-1 ; i++)
		{
			mHandlers[i].SetNext(mHandlers[i+1]);
		}
	}
	public static void Add(Handler handler)
	{
		if(mHandlers.Find(handler1 => handler1.GetHandlerType() == handler.GetHandlerType()) != null)
			return;
		mHandlers.Add(handler);
		Init();
	}
	public static void Remove(int index)
	{
		mHandlers.Remove(mHandlers[index]);
		Init();
	}
	//责任链入口
	public static void Execute(HandlerType handlerType, ref HandlerStruct value)
	{
		if(mHandlers.Count <= 0)
		{
			return;
		}
		mHandlers[0].Set(handlerType,ref value);
	}
}

首先,我们定义一个抽象类作为所有处理节点的基类,并且在此处我们使用模板方法,隐藏部分不可见逻辑,公开部分可见逻辑。

public abstract class Handler
{
	private Handler next;
	public void SetNext(Handler next)
	{
		this.next = next;
	}
	public virtual void Set(HandlerType handlerType,ref HandlerStruct value)
	{
		if(GetHandlerType() == handlerType)
		{
			HandlerRequest(ref value);
		}
		else if(next != null)
		{
			next.Set(handlerType,ref value);
		}
	}
	protected abstract void HandlerRequest(ref HandlerStruct value);
	public abstract HandlerType GetHandlerType();	
}
protected abstract void HandlerRequest(ref HandlerStruct value);

此段代码便是核心处理代码,抽象方法让子类去实现核心逻辑

public abstract HandlerType GetHandlerType();

此段代码是为了记录子类的处理数据特征,Set()函数会根据数据判断数据是否为可处理的。

可以处理则交给HandlerRequest(),如果不行,就抛给next节点(next节点不为空下)

以下为继承Handler的示例处理节点

FloatHandler.cs
public class FloatHandler : Handler
{
	protected override void HandlerRequest(ref HandlerStruct value)
	{
		Console.WriteLine($"floatHandler:{value.GetValue<FloatModel>()}");
	}
	public override HandlerType GetHandlerType()
	{
		return HandlerType.floatHandler;
	}

	public class FloatModel
	{
		public float value;

		public FloatModel(float value)
		{
			this.value = value;
		}
		public override string ToString()
		{
			return value.ToString();
		}
	}
}
StringHandler.cs
public class StringHandler : Handler
{
	protected override void HandlerRequest(ref HandlerStruct value)
	{
		Console.WriteLine($"stringHandler{value.GetValue<string>()}");
	}
	public override HandlerType GetHandlerType()
	{
		return HandlerType.stringHandler;
	}	
}

然后就是一个静态处理中心,用于统一接收数据,当然,这里只是测试,实际业务逻辑需要按照业务情况来定义,比如单例或者其他情况

HandlerCenter.cs
//处理中心
public static class HandlerCenter
{
	private static List<Handler> mHandlers = new List<Handler>();
	static HandlerCenter()
	{
	    mHandlers.Add(new FloatHandler());
		mHandlers.Add(new StringHandler());
	}
	private static void Init()
	{
		if(mHandlers.Count < 2)
		{
			return;
		}
		//单链式责任链
		for(int i = 0 ; i < mHandlers.Count-1 ; i++)
		{
			mHandlers[i].SetNext(mHandlers[i+1]);
		}
	}
	public static void Add(Handler handler)
	{
		if(mHandlers.Find(handler1 => handler1.GetHandlerType() == handler.GetHandlerType()) != null)
			return;
		mHandlers.Add(handler);
		Init();
	}
	public static void Remove(int index)
	{
		mHandlers.Remove(mHandlers[index]);
		Init();
	}
	//责任链入口
	public static void Execute(HandlerType handlerType, ref HandlerStruct value)
	{
		if(mHandlers.Count <= 0)
		{
			return;
		}
		mHandlers[0].Set(handlerType,ref value);
	}
}

(注意,这只是示例代码,实际上,因为我定义了Enum枚举变量作为数据特征,然后我还将处理节点存在了list里,所以我完全可以直接通过list查找符合特征的节点然后使用就行)

此处,我只是单纯的将两个节点按照顺序链接,形成一个单链表。

实际上我们可以使用更复杂的处理逻辑,因为如果处理节点过多,单链表从头开始遍历效率会大打折扣。

此外,根据学习链接的文章所示,责任链模式细分两种模式,一种就是目前这种单链完全责任模式,由一个节点完全处理所有数据,一种就是不完全责任链模式,一个节点只负责一个一部分,剩下的传给下一个节点,笔者个人认为,后者有一点像工厂流水线,适合和工厂模式结合使用,多人开发下,效率更高。

如下示例,我写了三个节点,

ImperfectHandler、ImperfectHandlerStr、ImperfectHandlerInt

和一个ImperfectModel类作为数据模板转递信息。

public class ImperfectHandler : Handler
{
	protected override void HandlerRequest(ref HandlerStruct value)
	{
		new ImperfectHandlerStr().Set(HandlerType.ImperfectHandler,ref value);
		Console.WriteLine(value.GetValue<ImperfectModel>()?.strValue);
		new ImperfectHandlerInt().Set(HandlerType.ImperfectHandler,ref value);
		Console.WriteLine(value.GetValue<ImperfectModel>()?.strValue);
	}

	public override HandlerType GetHandlerType()
	{
		return HandlerType.ImperfectHandler;
	}
	public class ImperfectModel
	{
		public string strValue;
		public float intValue;
	}
}

namespace Test
{
	public partial class ImperfectHandlerStr 
	{
		
	}
	public partial class ImperfectHandlerInt
	{
		
	}
}
namespace Test
{
	public partial class ImperfectHandlerStr : Handler
	{
		protected override void HandlerRequest(ref HandlerStruct value)
		{
			ImperfectHandler.ImperfectModel? model = value.GetValue<ImperfectHandler.ImperfectModel>();
			model.strValue = "Handler:"+model.intValue;
		}

		public override HandlerType GetHandlerType()
		{
			return HandlerType.ImperfectHandler;
		}
	}
	public partial class ImperfectHandlerInt : Handler
	{
		protected override void HandlerRequest(ref HandlerStruct value)
		{
			ImperfectHandler.ImperfectModel? model = value.GetValue<ImperfectHandler.ImperfectModel>();
			model.intValue ++;
			new ImperfectHandlerStr().Set( HandlerType.ImperfectHandler ,ref value);
		}

		public override HandlerType GetHandlerType()
		{
			return HandlerType.ImperfectHandler;
		}
	}
}

ImperfectHandler作为头节点,也就是责任链入口,它会依次实例化ImperfectHandlerStr和ImperfectHandlerInt并使用这两个节点分别处理ImperfectModel中的部分数据。

并且,ImperfectHandlerInt中又再次调用了ImperfectHandlerStr来处理字符串

 效果如图。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
原型模式是一种创建型设计模式,其提供了一种复制已有对象的方法来生成新对象的能力,而不必通过实例化的方式来创建对象。原型模式是通过克隆(浅复制或深复制)已有对象来创建新对象的,从而可以避免对象创建时的复杂过程。 在C#中,可以通过实现ICloneable接口来实现原型模式。ICloneable接口定义了Clone方法,该方法用于复制当前对象并返回一个新对象。需要注意的是,Clone方法返回的是Object类型,需要进行强制类型转换才能得到复制后的对象。 以下是一个简单的示例代码: ```csharp public class Person : ICloneable { public string Name { get; set; } public int Age { get; set; } public object Clone() { return MemberwiseClone(); } } // 使用示例 var person1 = new Person { Name = "Tom", Age = 20 }; var person2 = (Person)person1.Clone(); person2.Name = "Jerry"; Console.WriteLine(person1.Name); // 输出 "Tom" Console.WriteLine(person2.Name); // 输出 "Jerry" ``` 在上面的示例代码中,实现了一个Person类,并实现了ICloneable接口中的Clone方法来实现原型模式。复制对象时,使用MemberwiseClone方法进行浅复制,即只复制值类型的字段和引用类型字段的引用,而不复制引用类型字段所引用的对象。在使用示例中,首先创建一个Person对象person1,然后通过Clone方法复制一个新的对象person2,修改person2的Name属性后,输出person1和person2的Name属性,可以看到person1的Name属性并没有改变,说明person2是一个全新的对象。 需要注意的是,如果要实现深复制,即复制引用类型字段所引用的对象,需要在Clone方法中手动将引用类型字段复制一份。另外,使用原型模式时,需要注意复制后的对象和原对象之间的关系,如果复制后的对象修改了原对象的状态,可能会对系统产生意想不到的影响。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值