首先,本人是一名软件工程在读大三学生,在学习了C语言,C++语言之后,又对Java产生了浓厚的学习兴趣。特此写下相关的Java学习博文来记录自己的Java学习经历,同时提升自己的写作能力。
这是本人第一篇博文,希望大牛不惜赐教,对于本人的博文中无论是专业知识方面还是写作表述方面如有问题都能提出来,本人一定谦虚改正。
作为一名Java语言爱好者,深知OO思想与多态的重要性。今天观看了马士兵老师的java设计模式的Strategy模式课程之后,课程上留了一道题目:
封装一下商场的打折策略
在写完了对应的练习以后,分享出来,希望大家能与我交流心得。
首先,我们可以模拟一下环境。
目前有一个商场,商场之中我可以对任意的商品定义不同的打折策略。我们对商场中的电脑Computer和苹果Apple进行打折。
我首先创建了一个Computer类与Apple类,相关的定义如下:
public class Computer {
private double price;
public Computer(double price) {
super();
this.price = price;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public String toString() {
return "Computer [price=" + price + "]";
}
}
public class Apple {
private double price;
public Apple(double price) {
super();
this.price = price;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public String toString() {
return "Apple [price=" + price + "]";
}
}
接着定义一个Market类,其中有个静态方法用于对Computer对象做打折处理(我们假设现在要打五折):
public class Market {
public static void discount(Computer c) {
c.setPrice(c.getPrice()/2);
}
}
写一个Main类用来测试电脑打折情况:
public class Main {
public static void main(String[] args) {
Computer c = new Computer(3000);
System.out.println("打折前:");
Market.printPrice(c);
Market.discount(c);
System.out.println("打折后:");
Market.printPrice(c);
}
}
结果输出正确:
打折前:
Computer [price=3000.0]
打折后:
Computer [price=1500.0]
但此时出现了一个问题,我现在想要个Apple也打折,但是对于Market中的discount(Computer c)方法来说,接收的参数是Computer类对象的引用,也就是说,我现在想要对Apple打折,得重新写一个接收Apple类对象引用的discount方法,如此下去,不断增多的商品我必须不断地增加方法。显然,这样是不可行的。
如何解决呢?仔细想一下,对于这些商品来说,他们都有一个共同的特性:可以被打折(不是打折she)。那好,我们可以创建一个Discountable接口,该接口有一个discount()方法,所有实现这个接口的类都必须实现这个方法。我们让Computer与Apple类都实现这个接口并且实现其中的方法:
public interface Discountable {
void discount();
}
public void discount() {
price = price/2;
}
Apple类同理。同时修改Market类中的discount()方法如下:
public static void discount(Discountable disable) {
disable.discount();
}
这样一来,我把商场中的打折方式,交给了具体的能够打折的商品自己去处理。修改一下main函数中的相关内容,添加了Apple类对象。
public static void main(String[] args) {
Computer c = new Computer(3000);
Apple a = new Apple(10);
System.out.println("打折前:");
System.out.println(c);
System.out.println(a);
Market.discount(c);
Market.discount(a);
System.out.println("打折后:");
System.out.println(c);
System.out.println(a);
}
看看结果:
打折前:
Computer [price=3000.0]
Apple [price=10.0]
打折后:
Computer [price=1500.0]
Apple [price=5.0]
好了,现在我可以对不同的商品进行打折了,只要我这件商品实现了Discountable接口,必定实现其中的discount()方法,这样一来具体的实现交给具体的类。但还有一个问题我们还没有解决:对于同种商品的不同打折策略的实现,双十一我想打5折,平常会员日我想打75折,开店十周年我想打1折,这该怎么办呢?也许你会想,我在Computer里写几个方法分别能够打不同的折扣,然后再discount()里面调用。我已开始也觉得这样就可以了,但是仔细一想,成千上百种打折策略,我是不是都要往类里面添加方法呢?那就没有意义了。
其实我们可以定义一个打折器接口Discounter
public interface Discounter {
void discount(Object o);
}
接着,我新写三个类:NormalPrice、Computer50PriceDiscounter、
Apple75PriceDiscounter它们均实现了Discounter接口,如下:
public class NormalPrice implements Discounter {
public void discount(Object o) {}
}
NormalPrice不做打折处理。
public class Computer50PriceDiscounter implements Discounter {
public void discounter(Object o) {
Computer c = (Computer)o;
c.setPrice(c.getPrice()/2);
}
}
Computer50PriceDiscounter对Computer打5折。
public class Computer50PriceDiscounter implements Discounter {
public void discount(Object o) {
Computer c = (Computer)o;
c.setPrice(c.getPrice()/2);
}
}
Apple75PriceDiscounter对Apple打75折。
public class Apple75PriceDiscounter implements Discounter {
public void discount(Object o) {
Apple a = (Apple)o;
a.setPrice(a.getPrice()*0.75);
}
}
好了,在Computer类中我添加一个成员变量dis,并且修改原来的discount方法,同时给dis添加set方法,如下:
private Discounter dis = new NormalPrice();
//默认不打折
public void setDiscounter(Discounter dis) {
this.dis = dis;
}
public void discount() {
dis.discount(this);
}
Apple同理。于是,具体的打折我又交给可以打折的商品类中的打折器去处理了。接着修改main中的方法,如下:
public static void main(String[] args) {
Computer c = new Computer(3000);
Apple a = new Apple(10);
System.out.println("打折前:");
System.out.println(c);
System.out.println(a);
c.setDiscounter(new Computer50PriceDiscounter());
a.setDiscounter(new Apple75PriceDiscounter());
Market.discount(c);
Market.discount(a);
System.out.println("打折后:");
System.out.println(c);
System.out.println(a);
}
测试一下:
打折前:
Computer [price=3000.0]
Apple [price=10.0]
打折后:
Computer [price=1500.0]
Apple [price=7.5]
没有问题。以后,我想要做任何的打折,只需要创建一个实现了Discounter接口的类并实现其中的discount方法,在该方法中进行具体的打折策略,之后只需要new出该具体打折器通过setDiscounter方法配置给类中的dis就可以完成具体的打折可。
心得
对于Strategy模式,我目前的一些理解如下:strategy针对的是虽然有各种各样的情况但其本质都一样的问题。
在本例中,打折有千变万化的情况,但其本质都是打折。商场可以对商品进行打折,那么这些商品必然具有共同的属性:discountable(可折扣的),于是这些商品必然自身就能够实现打折方法,于是,我们就能够把打折方式从商场的角度转向自身。我(Market)想打折的时候调用discount方法就是了,具体怎么实现,由你(商品)自己的discount来做,基于这一点可以解决不同商品之间的打折的不同实现。
那么对于同类商品的不同打折模式,不管你怎么打折,你都是在打折,那我就创建一个Discounter打折器接口,放到你这个可打折的类中,到时候你想怎么打折,Ok,你自己去实现Discounter接口并实现其中的方法,实现完了以后new出来,set到我的Discounter成员变量中去,我(商品)在实现打折时,就通过你这个具体的打折器调用具体的打折策略就行了。
第一次写希望大牛能提出宝贵意见。