策略模式它的意图是封装算法,它认为算法是一个整体,是相互独立的,并且是可以相互替换的,让算法的行为独立于客户。
命令模式它的意图是解耦,它让执行命令者和发布命令者分离。
实现一个压缩和解压缩的功能,这个功能有两种算法:一种是gzip,一种是zip。
1. 策略模式的实现:
代码:
interface Algorithm{
public void zipExecute();
public void gzipExecute();
}
class CompressAlgorithm implements Algorithm{
public void zipExecute() {
System.out.println("zip压缩成功!");
}
public void gzipExecute() {
System.out.println("gzip压缩成功");
}
}
class UnCompressedAlgorithm implements Algorithm{
public void zipExecute() {
System.out.println("Zip解压成功!");
}
public void gzipExecute() {
System.out.println("gzip解压成功!");
}
}
class Context{
private Algorithm algorithm;
public Context(Algorithm algorithm) {
super();
this.algorithm = algorithm;
}
public void zipExecute(){
algorithm.zipExecute();
}
public void gzipExecute(){
algorithm.gzipExecute();
}
}
public class Client {
public static void main(String[] args) {
Context context = new Context(new CompressAlgorithm());
context.gzipExecute();
context.zipExecute();
context = new Context(new UnCompressedAlgorithm());
context.gzipExecute();
context.zipExecute();
}
}
策略模式中,虽然有两个算法,一个是zip另外一个是Gzip,但是对于调用者来说,这两个算法没有本质区别,只是“形式”不一样而已。对于Client来说,我用哪个算法都无所谓,关键是能帮忙压缩和解压就可以了。
2. 命令模式:
我们把上面的模型比作去餐馆点菜,客人(Client)是请求者,通过服务员(Invoker)向厨师(Receiver)发送点菜请求(Command)。命令对应具体接受者,也就是哪一道菜对应哪个厨师。命令模式的意图在于解耦,即,客人不和厨师直接打交道。
interface IReceiver{
public void zipExecute();
public void gzipExecute();
}
class CompressReceiver implements IReceiver{
@Override
public void zipExecute() {
System.out.println("Zip压缩成功");
}
@Override
public void gzipExecute() {
System.out.println("Gzip压缩成功");
}
}
class UnCompressReceiver implements IReceiver{
@Override
public void zipExecute() {
System.out.println("Zip解压成功");
}
@Override
public void gzipExecute() {
System.out.println("GZip解压成功");
}
}
abstract class Command{
protected IReceiver compressReceiver = new CompressReceiver();
protected IReceiver unCompressReceiver = new UnCompressReceiver();
public abstract void execute();
}
class GZipCompressCommand extends Command{
@Override
public void execute() {
super.compressReceiver.gzipExecute();
}
}
class GZipUnCompressCommand extends Command{
@Override
public void execute() {
super.unCompressReceiver.gzipExecute();
}
}
class ZipCompressCommand extends Command{
@Override
public void execute() {
super.compressReceiver.zipExecute();
}
}
class ZipUnCompressCommand extends Command{
@Override
public void execute() {
super.unCompressReceiver.zipExecute();
}
}
class Invoker{
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void deliverCommand(){
this.command.execute();
}
}
public class Client {
public static void main(String[] args) {
Invoker invoker = new Invoker();
invoker.setCommand(new ZipCompressCommand());
invoker.deliverCommand();
}
}
3. 改造接口
3.1 为了体现命令模式的解耦意图,我们对接口IReceiver进行改造,按职责来划分,如下:
interface IReceiver{
public void compress();
public void uncompress();
}
class ZipReceiver implements IReceiver{
@Override
public void compress() {
System.out.println("Zip压缩成功");
}
@Override
public void uncompress() {
System.out.println("Zip解压成功");
}
}
class GzipReceiver implements IReceiver{
@Override
public void compress() {
System.out.println("Gzip压缩成功");
}
@Override
public void uncompress() {
System.out.println("Gzip解压成功");
}
}
abstract class Command{
protected IReceiver zipReceiver = new ZipReceiver();
protected IReceiver gzipReceiver = new GzipReceiver();
public abstract void execte();
}
class ZipCompressCommand extends Command{
@Override
public void execte() {
super.zipReceiver.compress();
}
}
class ZipUnCompressCommand extends Command{
@Override
public void execte() {
super.zipReceiver.uncompress();
}
}
class GZipCompressCommand extends Command{
@Override
public void execte() {
super.gzipReceiver.compress();
}
}
class GZipUnCompressCommand extends Command{
@Override
public void execte() {
super.gzipReceiver.uncompress();
}
}
class Invoker{
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void deliverCommand(){
this.command.execte();
}
}
public class Client {
public static void main(String[] args) {
Invoker invoker = new Invoker();
invoker.setCommand(new ZipCompressCommand());
invoker.deliverCommand();
}
}
我们发现无论底层命令实现怎么修改,客户都都不需要发生变化,这就体现了命令模式的解耦的意图。
3.2 而反观策略模式,如果要按职责进行修改的话,就要修改它的抽象算法:
interface Algorithm{
public void compress();
public void uncompress();
}
class Zip implements Algorithm{
@Override
public void compress() {
System.out.println("zip压缩成功");
}
@Override
public void uncompress() {
System.out.println("zip解压成功");
}
}
class GZip implements Algorithm{
@Override
public void compress() {
System.out.println("Gzip压缩成功");
}
@Override
public void uncompress() {
System.out.println("Gzip解压成功");
}
}
class Context{
private Algorithm algorithm;
public Context(Algorithm algorithm) {
super();
this.algorithm = algorithm;
}
public void compress(){
algorithm.compress();
}
public void uncompress(){
algorithm.uncompress();
}
}
public class Client {
public static void main(String[] args) {
Context context = new Context(new GZip());
context.compress();
context = new Context(new Zip());
context.compress();
}
}
策略模式的初衷就是封装算法,而我们这样做就打破了策略模式对算法的封装,违背了它的初衷。
而命令模式却可以随意对接口进行修改,按职责来划分,是因为命令模式着重于请求者和接受者的解耦,只要不影响请求者就行了。这才是命令模式的意图。
小结:
- 两种模式的关注点不同,策略模式关注的是算法的完整性和封装性,只要具备了这两个条件才能保证其可切换。
- 职责,比如菜单栏里有”复制”,“剪切”等,命令模式对应的是“复制”,“剪切”等各个功能,而策略模式对应的是“复制”这一个功能,但是“复制”有各种形式,我们可以用鼠标点击复制,也可以用快捷键。但无论怎么样,都是在做同一样事情,那就是复制。