假设某服装店正在进行促销活动。
T恤打八折,毛衣打五折,而衬衫价格不变,
怎样获得要购买的衣服的实际出售价格?
第一种实现方式:
[Clothes.java] 衣服类
-
public abstract class Clothes {
-
private double price;
-
public double getPrice ( ) {
-
return price;
-
}
-
public void setPrice ( double price ) {
-
this. price = price;
-
}
-
}
[Shirt.java] 衬衫类
-
public class Shirt extends Clothes {
-
}
[Sweater.java] 毛衣类
-
public class Sweater extends Clothes {
-
}
[TShirt.java] T恤类
-
public class TShirt extends Clothes {
-
}
[CountClothesPriceSum.java] 计算总价类
-
import java.util.*;
-
-
public class CountClothesPriceSum {
-
-
private List<Clothes> list = new ArrayList<Clothes> ( );
-
-
public void addToList (Clothes clothes ) {
-
list. add (clothes );
-
}
-
-
public double countPriceSum ( ) {
-
double sum = 0.0;
-
for ( int i= 0; i<list. size ( ); i++ ) {
-
if (list. get (i ) instanceof TShirt ) {
-
sum += list. get (i ). getPrice ( )* 0.8;
-
} else {
-
if (list. get (i ) instanceof Sweater ) {
-
sum += list. get (i ). getPrice ( )* 0.5;
-
} else {
-
sum += list. get (i ). getPrice ( );
-
}
-
}
-
}
-
return sum;
-
}
-
}
若此时,裙子跳楼价二折,又要如何?
我们怎样使所编写的代码能够扩展?
看看下面的实现:
//忘记怎么写了 - -。。 且先放着。。
// 总之仿佛是做一个Discount的接口,
// 让Clothes去实现它
// 它有一个discount属性,
// 即使不打折扣,也可以设置其为1
也许这是一个能解决打折问题的好方法,
但是……
但是,如果再来一个促销……满100返还20呢?
我们再定义一个Onsale的接口,让Clothes去实现?
不不不,这样做的话,
促销的产品多余了打折扣的方法,
而打折扣的产品则会多余促销的方法……
那么,我们该如何实现呢?
因此,我们在这里使用策略模式:
[Clothes.java]
-
public abstract class Clothes {
-
private double price;
-
-
public double getPrice ( ) {
-
return policy. getPrice (price );
-
}
-
public void setPrice ( double price ) {
-
this. price = price;
-
}
-
return policy;
-
}
-
this. policy = policy;
-
}
-
-
}
[Policy.java] 计价类
-
-
public double getPrice ( double price ) {
-
return price;
-
}
-
}
[DiscountPolicy.java] 折扣计价类
-
private double discount;
-
-
public DiscountPolicy ( double discount ) {
-
this. discount = discount;
-
}
-
public void setDiscount ( double discount ) {
-
this. discount = discount;
-
}
-
-
public double getPrice ( double price ) {
-
return price*discount;
-
}
-
}
[OnsalePolicy.java] 促销计价类
-
-
private int basePrice;
-
-
private double returnMoney;
-
-
public OnsalePolicy ( int basePrice, double returnMoney ) {
-
this. basePrice = basePrice;
-
this. returnMoney = returnMoney;
-
}
-
-
public double getPrice ( double price ) {
-
if (price>=basePrice ) {
-
return price-returnMoney;
-
}
-
return price;
-
}
-
public void setBasePrice ( int basePrice ) {
-
this. setBasePrice (basePrice );
-
}
-
-
public void setReturnMoney ( int returnMoney ) {
-
this. returnMoney = returnMoney;
-
}
-
-
}
[TShirt.java][Shirt.java][Sweater.java][Skirt.java]等衣服的子类略。
[CountClothesPriceSum.java] 计算总价类
-
public class CountClothesPriceSum {
-
-
private List<Clothes> list = new ArrayList<Clothes> ( );
-
-
public void addToList (Clothes clothes ) {
-
list. add (clothes );
-
}
-
-
public double countPriceSum ( ) {
-
double sum = 0.0;
-
for ( int i= 0; i<list. size ( ); i++ ) {
-
sum += list. get (i ). getPrice ( );
-
}
-
return sum;
-
}
-
}
这样,如果还有新的计价策略,
我们只需要写一个类来继承Policy,重写它的getPrice(double)方法即可。
这便做到了“对扩展开放,对修改关闭。”
最后附上改进用的UT:
-
public class TestCases extends TestCase {
-
public void testCase1 ( ) {
-
CountClothesPriceSum count = new CountClothesPriceSum ( );
-
-
Shirt shirt = new Shirt ( );
-
shirt. setPrice ( 32 );
-
count. addToList (shirt );
-
assertEquals (count. countPriceSum ( ), 32.0 );
-
-
TShirt tShirt = new TShirt ( );
-
tShirt. setPrice ( 20 );
-
tShirt. setPolicy ( new DiscountPolicy ( 0.8 ) );
-
count. addToList (tShirt );
-
assertEquals (count. countPriceSum ( ), 48.0 );
-
-
DiscountPolicy discountPolicy = new DiscountPolicy ( 0.5 );
-
tShirt. setPolicy (discountPolicy );
-
assertEquals (count. countPriceSum ( ), 42.0 );
-
-
Sweater sweater = new Sweater ( );
-
sweater. setPrice ( 50 );
-
sweater. setPolicy (discountPolicy );
-
count. addToList (sweater );
-
assertEquals (count. countPriceSum ( ), 67.0 );
-
}
-
// For OnsalePolicy
-
public void testCase2 ( ) {
-
CountClothesPriceSum count = new CountClothesPriceSum ( );
-
-
Shirt shirt = new Shirt ( );
-
shirt. setPolicy ( new OnsalePolicy ( 100, 20 ) );
-
shirt. setPrice ( 80 );
-
count. addToList (shirt );
-
assertEquals (count. countPriceSum ( ), 80.0 );
-
-
shirt. setPrice ( 100 );
-
assertEquals (count. countPriceSum ( ), 80.0 );
-
-
shirt. setPrice ( 120 );
-
assertEquals (count. countPriceSum ( ), 100.0 );
-
-
OnsalePolicy onsalePolicy = new OnsalePolicy ( 50, 5 );
-
Sweater sweater = new Sweater ( );
-
sweater. setPrice ( 75 );
-
sweater. setPolicy (onsalePolicy );
-
count. addToList (sweater );
-
assertEquals (count. countPriceSum ( ), 170.0 );
-
-
sweater. setPrice ( 20 );
-
assertEquals (count. countPriceSum ( ), 120.0 );
-
}
-
-
// For Skirt
-
public void testCase3 ( ) {
-
CountClothesPriceSum count = new CountClothesPriceSum ( );
-
Skirt skirt = new Skirt ( );
-
skirt. setPrice ( 50 );
-
count. addToList (skirt );
-
assertEquals (count. countPriceSum ( ), 50.0 );
-
-
skirt. setPolicy ( new DiscountPolicy ( 0.3 ) );
-
assertEquals (count. countPriceSum ( ), 15.0 );
-
-
skirt. setPolicy ( new OnsalePolicy ( 30, 5 ) );
-
assertEquals (count. countPriceSum ( ), 45.0 );
-
-
}
-
}
策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。(The Strategy Pattern defines a family of algorithms,encapsulates each one,and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it.) 1、 多个类只区别在表现行为不同,可以使用Strategy模式,在运行时动态选择具体要执行的行为。(例如FlyBehavior和QuackBehavior) 2、 需要在不同情况下使用不同的策略(算法),或者策略还可能在未来用其它方式来实现。(例如FlyBehavior和QuackBehavior的具体实现可任意变化或扩充) 3、 对客户(Duck)隐藏具体策略(算法)的实现细节,彼此完全独立。 优点: 1、 提供了一种替代继承的方法,而且既保持了继承的优点(代码重用)还比继承更灵活(算法独立,可以任意扩展)。 2、 避免程序中使用多重条件转移语句,使系统更灵活,并易于扩展。 3、 遵守大部分GRASP原则和常用设计原则,高内聚、低偶合。 缺点: 1、 因为每个具体策略类都会产生一个新类,所以会增加系统需要维护的类的数量。 |