设计模式----策略模式(推送的实现)
一、何为策略模式
策略模式是行为型模式的一种,主要用于需要使用不同的算法来处理不同的数据对象时使用,是一种可以在运行时选择算法的设计模式。也称为政策模式。
主要解决:在有多种算法相似的情况下,使用 if...else 所带来的复杂和难以维护。
何时使用:一个系统有许多许多类,而区分它们的只是他们直接的行为。
如何解决:将这些算法封装成一个一个的类,任意地替换。
应用实例: 1、诸葛亮的锦囊妙计,每一个锦囊就是一个策略。 2、旅行的出游方式,选择骑自行车、坐汽车,每一种旅行方式都是一个策略。 3、JAVA AWT 中的 LayoutManager。
优点: 1、算法可以自由切换。 2、避免使用多重条件判断。 3、扩展性良好。
缺点: 1、策略类会增多。 2、所有策略类都需要对外暴露。
使用场景: 1、如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。 2、一个系统需要动态地在几种算法中选择一种。 3、如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。
注意事项:如果一个系统的策略多于四个,就需要考虑使用混合模式,解决策略类膨胀的问题。
二、策略模式的UML图
抽象策略类(Strategy):定义一个所有算法都支持的通用接口,内容类使用这个接口调用由具体策略实现的算法。
具体策略类(OperationAdd、OperationSubstract、OperationMultiply):实现一个相应的算法
内容类(Context):包含一个对策略对象的引用,可定义一个用于策略类访问的接口。当需要进行特定的操作时会从对应的策略类对象调用相应的算法。内容类本身不会察觉对策略类的执行。如果有必要的话,还可以定义专用的对象来传递从内容类对象到策略类的数据。内容类接受来自客户端的数据,并将其委托给策略类对象。而策略类通常是客户端创建,并传递给内容类。
三、策略类的应用场景及创建步骤
在计算机算法中,我们可以实现对列表中数据的排序,其方法有冒泡排序、快速排序、堆排序等不同的算法。然而在实际运用中则一次只使用其中的一个算法。为了在不同的场景中权衡计算机的运算速度和存储空间大小等,可以使用不同的算法。
再比如,我们乘车去某地,可以选择出租、大巴、城市交通工具等等方式,每种方式在费用、便利性、时间等成本上具有不同,我们会根据不同的场合选用不同的策略。
接下来,我们看一下策略模式的创建步骤
1)识别客户端可能需要的算法。既然是对算法策略的选择,第一步必当是算法的识别
2)在接口中指定该算法的签名(原型定义)。
3)在派生类中提供可选择的细节。即对算法的具体实现
4)将客户端算法与接口耦合。即在客户端中通过不同场合下的判断决定调用不同策略类提供的算法
四、某个具体的实现案例
在这里,我们看一个关于推送的案例。在现在电商无比潇洒的光景下,各大电商为了迎合自己客户的需求,希望提供自己服务的质量。于是,在用户打开他们客户端的时刻,他们便急于将自己的产品推送给客户。于是产生了问题----客户想要什么。不同的客户有不同的需求,不能只推送电商自己想要急于出售的东西。于是电商们建立了自己的数据引擎,希望通过对客户历史上的商品浏览记录、购买记录来预知客户的需求。
首先对上段文字做一个小小的分析,上面涉及到了诸如客户(Customer)、引擎(Engine)等实体,我们可以此建立我们的类。而引擎需要获取客户的相关数据,因此需要客户提供给引擎一个可访问的接口。而引擎负责给客户提供数据支持,为了掩盖不同引擎的差别,也应当提供一个引擎的接口。
然而,客户或许未能登录,或许第一次进入系统而没有相关的浏览数据信息,该怎么办呢?
需要不同的引擎支持。
由此我们建立UML图进一步分析
如图所示,我们建立了对客户(Customer)的接口ICustomer,对策略类的接口IAdvisor。
假设有三个数据引擎:
RefEngine:针对登录用户能够根据引用到的客户信息来推送客户想要的数据信息
OtherRecEngine:其他推荐引擎,指的是对于登录的用户,虽然能够获取用户的一些信息但是由于用户的商品信息过少或者其他原因,通过一些供货商(vender)进行主动推送
RandomEngine:随机引擎,当没有足够的数据提供给另外两个引擎时(用户都未曾登录),使用随机生成推送的方法推送信息
注:由于三个引擎只使用其算法实现,故均只生成单例
下面,我们对该实例进行实现。
五、具体实现
1.对客户及对推送引擎接口的实现
1.1 Java实现
引擎接口
1 public interface IAdvisor { 2 public Object Recommend(Customer c); 3 }
客户接口
1 public interface ICustomer { 2 public String getInfo(); 3 }
1.2 c#实现
引擎接口
1 interface IAdvisor 2 { 3 Object Recommend(Customer c); 4 }
客户接口
1 interface ICustomer 2 { 3 String getInfo(); 4 }
2.对三个引擎的实现(策略类)
注:由于每个引擎只需使用其中的算法实例,故每个引擎只需存在单一实例,通过简单的方法实现单例
2.1 Java实现
1 public class OtherRecEngine implements IAdvisor{ 2 //Using Singleton pattern to only generate one instance 3 public static final OtherRecEngine singleton=new OtherRecEngine(); 4 5 private OtherRecEngine(){}; 6 7 //using Engine to generate outcome with the info of customer 8 public Object Recommend(Customer c){ 9 return new String("Using OtherRecEngine to generate outcome with the infomation of the customer: \""+c.getInfo()+"\""); 10 } 11 12 }
1 public class RefEngine implements IAdvisor{ 2 //Using Singleton pattern to only generate one instance 3 public static final RefEngine singleton=new RefEngine(); 4 5 private RefEngine(){} 6 7 //using Engine to generate outcome with the info of customer 8 public Object Recommend(Customer c){ 9 return new String("Using RefEngine to generate outcome with the infomation of the customer: \""+c.getInfo()+"\""); 10 } 11 }
1 public class RandomEngine implements IAdvisor{ 2 //Using Singleton pattern to only generate one instance 3 public static final RandomEngine singleton=new RandomEngine(); 4 5 private RandomEngine(){}; 6 7 //Generate outcome with no info 8 public Object Recommend(Customer c){ 9 return new String("Generate using Random Engine"); 10 } 11 }
2.2 c#实现
1 class RefEngine : IAdvisor 2 { 3 //Using singleton pattern for just on instance of this class 4 public static readonly RefEngine singleton = new RefEngine(); 5 6 private RefEngine() { } 7 8 //using Engine to generate outcome with the info of customer 9 public object Recommend(Customer c) 10 { 11 return "Using RefEngine to generate outcome with the infomation of the customer: \"" + c.getInfo() + "\""; 12 } 13 }
1 class OtherRecEngine:IAdvisor 2 { 3 //Using Singleton pattern to only generate one instance 4 public static readonly OtherRecEngine singleton = new OtherRecEngine(); 5 6 private OtherRecEngine() { } 7 8 //using Engine to generate outcome with the info of customer 9 public object Recommend(Customer c) 10 { 11 return "Using OtherRecEngine to generate outcome with the infomation of the customer: \"" + c.getInfo() + "\""; 12 } 13 }
1 class RandomEngine : IAdvisor 2 { 3 //Using Singleton pattern to only generate one instance 4 public static readonly RandomEngine singleton = new RandomEngine(); 5 6 private RandomEngine() { } 7 8 //Generate outcome with no info 9 public object Recommend(Customer c) 10 { 11 return "Generate using Random Engine"; 12 } 13 }
3.实现客户类
在客户类的实现中通过showAdvices该方法获取从引擎传来的数据,而不同的场景下选择的引擎不同,故通过场景的判断来实现对不同场景的判断并通过获取到的引擎实例来获得推送消息
3.1 Java实现
1 public class Customer implements ICustomer{ 2 public Customer(){}; 3 //the stategy 4 private IAdvisor _advisor; 5 6 //info:Customer's infomation login:if Customer login 7 private String info; 8 private boolean login=false; 9 10 //if vender propel info 11 private boolean venderSuggest=false; 12 13 //Using the Strategy 14 public void showAdvices(){ 15 if(_advisor==null){ 16 if(login==true){ 17 _advisor=RefEngine.singleton; 18 } 19 else if(venderSuggest==true){ 20 _advisor=OtherRecEngine.singleton; 21 } 22 else 23 _advisor=RandomEngine.singleton; 24 } 25 System.out.println(_advisor.Recommend(this)); 26 } 27 28 public boolean isLogin(){ 29 return login; 30 } 31 32 public void Login(){ 33 login=true; 34 } 35 36 public boolean isVenderSuggest(){ 37 return venderSuggest; 38 } 39 40 public void setVenderSuggest(boolean b){ 41 venderSuggest=b; 42 } 43 44 public String getInfo(){ 45 return "I'm a customer"; 46 } 47 48 }
3.2 c#实现
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace Strategy 8 { 9 class Customer:ICustomer 10 { 11 private IAdvisor _advisor; 12 private string info; 13 private bool login = false; 14 private bool venderSuggest=false; 15 16 public Customer() { } 17 //If vender have something to recommend to customer 18 public bool VenderSuggest 19 { 20 get 21 { 22 return venderSuggest; 23 } 24 25 set 26 { 27 venderSuggest = value; 28 } 29 } 30 //if customer logged in 31 public void Login() 32 { 33 login = true; 34 } 35 36 //Execute the strategy 37 public void showAdvices() 38 { 39 if (_advisor == null) 40 { 41 if (login == true) 42 { 43 _advisor = RefEngine.singleton; 44 } 45 else if (venderSuggest == true) 46 { 47 _advisor = OtherRecEngine.singleton; 48 } 49 else 50 _advisor = RandomEngine.singleton; 51 } 52 Console.WriteLine(_advisor.Recommend(this)); 53 } 54 55 //get the info of customer 56 public string getInfo() 57 { 58 return "I'm a customer"; 59 } 60 } 61 }
4.客户端(控制台)调用
4.1 Java实现
1 public class Program { 2 public static void main(String[] args){ 3 4 //Initialize customers 5 Customer c1=new Customer(); 6 c1.Login(); 7 c1.setVenderSuggest(true); 8 9 Customer c2=new Customer(); 10 c2.setVenderSuggest(true); 11 12 Customer c3=new Customer(); 13 14 c1.showAdvices(); 15 c2.showAdvices(); 16 c3.showAdvices(); 17 } 18 }
运行实例:
4.2 c#实现
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 //Initialize all customers 6 Customer c1 = new Customer(); 7 c1.Login(); 8 9 Customer c2 = new Customer() 10 { 11 VenderSuggest =true 12 }; 13 14 Customer c3 = new Customer(); 15 16 c1.showAdvices(); 17 c2.showAdvices(); 18 c3.showAdvices(); 19 } 20 }
运行实例: