做网站的IT行业,电商视觉设计是干什么的,301的网站用什么来做,长泰建设局网站策略模式
例#xff1a;设计一个模拟鸭子游戏#xff0c;游戏中有各种鸭子#xff0c;一边戏水一边嘎嘎叫。
所以学习设计模式前#xff0c;我们最先想到的就是设置一个超类#xff0c;并让其他子类去继承这个类#xff0c;UML图如下#xff1a;
* *
但是#xff0…
策略模式
例设计一个模拟鸭子游戏游戏中有各种鸭子一边戏水一边嘎嘎叫。
所以学习设计模式前我们最先想到的就是设置一个超类并让其他子类去继承这个类UML图如下
* *
但是程序需求是会经常变动的若给游戏中加入飞行方法以及玩具小黄鸭呢并不是所有鸭子都可以飞也并不是所有鸭子都是嘎嘎叫。
此时你可能会想在父类添加相应方法在子类重写就可以让不同鸭子的同一方法具有不同表现了!
然而当子类数量剧增时你都要到对应子类去逐个修改这将是个复杂又无聊的工作单独使用接口也同样会使代码量变多出现许多重复性代码。 那么还有其他更好的方式来添加飞行方法吗
有就是委托。我们可以把委托者和被委托者想成has-a有一个的关系。比如上面这个例子鸭子被委托者有一个飞行行为委托者
把飞行想成Duck的一个功能Duck具有该功能即Duck本身含有飞行行为的实例可以调用飞行行为的飞行方法。
找出易于变化的部分把他们独立起来
把会变化的部分取出封装起来好让其他部分不会受到影响。代码变化引起的不经意后果变少系统将变得更有弹性。 针对接口编程而不是针对实现编程
将会变化的部分放在类中此类专门提供某行为接口的实现这样主类就不需要知道行为的实现细节。 多用组合少用继承
相应的UML图 实际代码
设计两个接口类让所有飞行类及所有叫声类都实现对应的接口 接口 FlyBehavior 1 2 3 public interface flyBehavior{ public void fly(); }
接口QuackBehavior 1 2 3 public interface QuackBehavior{ public void quack(); }
这样设计接口让飞行与叫声的动作可以被其他对象复用又可以新增一些行为类而不会影响既有的行为类也不会影响到“使用”行为的类。
编写对应的类实现接口让这些类负责实现具体的行为。 1 2 3 4 5 6 7 8 9 10 11 12 13 public class FlyNoWay implements FlyBehavior { Override public void fly() { System.out.println(我不会飞); } } * * * * * * * * * * * * * * * * * * * * * * *分割线 * * * * * * * * * * * * * * * * * * * * public class Quack implements QuackBehavior { Override public void quack() { System.out.println(Quack); } }
在此省略其他行为类的展示...
在Duck类中怎加两个实例变量声明为我们刚刚建立的接口类型这样Duck都能在运行时动态地设置这些变量并保证引用正确的行为类型。
Duck类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 //抽象化 public abstract class Duck { //接口类型的实例变量 QuackBehavior quackBehavior; FlyBehavior flyBehavior; public Duck() { } //设定display()方法为抽象的让每个继承的类都必须实现它 public abstract void display(); public void performFly() { //将行为的实现委托给flyBehavior引用的对象 flyBehavior.fly(); } public void performQuack() { //将行为的实现委托给quackBehavior引用的对象 quackBehavior.quack(); } public void swim() { System.out.println(所有鸭子都能会游泳); } //建立一个seter方便动态地设定行为 public void setFlyBehavior(FlyBehavior fb) { flyBehaviorfb; } public void setQuackBehavior(QuackBehavior qb) { quackBehaviorqb; } }
MallardDuck类 1 2 3 4 5 6 7 8 9 10 11 public class MallardDuck extends Duck{ public MallardDuck() { quackBehaviornew Quack(); flyBehaviornew FlyWithWings(); } public void display() { System.out.println(我是只野鸭); } }
MiniDuckSimulator类 1 2 3 4 5 6 7 8 9 10 11 12 public class MiniDuckSimulator { public static void main(String[] args) { Duck mininew MallardDuck(); /*这会调用MallardDuck类继承来的performFly方法 *进而委托给FlyBehavior对象处理即调用继承来的 *对象flyBehavior引用的FlyWithWings()。 */ mini.performFly(); mini.performQuack(); } }
动态设定行为
模型鸭既不会飞也不会叫但我们在Duck类中添加了seter方法以便动态设定行为给模型鸭添加一个火箭助推器让它飞起来。 ModelDuck类 1 2 3 4 5 6 7 8 9 10 11 public class ModelDuck extends Duck{ Override public void display() { System.out.println(我是模型鸭); } public ModelDuck() { flyBehavior new FlyNoWay(); quackBehavior new Quack(); } }
对MiniDuckSimulator类稍作改动 1 2 3 4 5 6 7 8 9 public class MiniDuckSimulator { public static void main(String[] args) { Duck modelnew ModelDuck(); model.performFly(); //FlyRocketPower()是继承飞行接口的一个飞行行为类 model.setFlyBehavior(new FlyRocketPower()); model.performFly(); } }
输出将是 1 2 我不会飞 我通过火箭飞起来了
总结
策略模式的三项原则
1、找出应用中可能需要变化之处把它们独立出来不要和那些无需变化的代码混在一起。
2、针对接口编程而不是针对实现编程
3、多用组合少用继承
分离变与不变。回忆之前的需求可以发现不变的是swim变的是fly与quack。虽然swim和fly都是鸭子的行为但是swim不怎么变化它可以利用继承来实现代码复用而飞行方式却有很多种无法继承因此需要将飞行行为抽出来各自实现让Duck实现类拥有飞行行为实例达到操作飞行行为的目的。这种思想就像零件的组装主体是不变的零件有各种相同功能不同性能的各种款式这样可以做出不同的产品。 另外策略模式还有一个好处是可以动态变化行为比如木头鸭子原来是不会飞的它用setFlyBehavior设置不会飞行后来设计师给他装上了引擎翅膀它可以再次通过setFlyBehavior在运行时动态变更飞行行为。