前言:
了解OO并不一定能设计出好的系统,设计模式实际上是一些构建OO系统的隐藏经验,可以在构建系统时提供一个大致的思路。所以,要辩证的看设计模式,不能迷信,也不能不信。
本文使用的开发语言为java,只涉及设计模式的基本思想,并不深究java的语法和设计。
本文主要介绍:策略模式,观察者模式,装饰模式以及工厂模式。
策略模式定义了算法族,分别封装起来,让他们之间可以互相替换,此模式可以让算法的变化独立于使用算法的客户。
注意:
总的来说,就是尽可能分离出is-a,has-a,has-a尽可能通过接口或者抽象类实现,避免通过继承实现导致不能cover住整体的调整。
而且可以通过组合和委托来实现运行时动态扩展的效果。
(我知道自己这段写的不像人话,水平所限,暂时没啥好的表述。。。)
在对象之间定义一种一对多的依赖,这样当一个对象改变状态,依赖他的对象都会收到通知,并自动更新。
直观来说,就是一种发布订阅模式,不过到底是pull还是push不确定。一个典型的观察者模式是一个发布者对应多个订阅者,发布者的某些状态改变后,向订阅者发送通知,同步变化。
具体实现上,可以自己手写也可以通过java.util.Observer和Observable实现,当然在java9之后的版本中Observer相关的实现被废弃了,详细原因有很多,可自行百度。针对这种情况,java包也提供了相应的替代方法,例如java.beans.PropertyChangeEvent
以及java.util.concurrent.Flow
等。
一个关键的设计原则是:类应该对扩展开放,对修改关闭。 也叫做开放-关闭原则。装饰者模式中这种原则表现的非常明显,实际上,这种思想在策略模式以及观察者模式中也有一定体现。
直观理解:装饰者模式也可以形象地理解为“套娃模式”,需要一层层的剥开,每一层就是一个装饰器,这样可以在尽可能不影响类实现的基础上扩展功能。
关键要点:
与其说是一种设计模式,常见的简单工厂更像一个编程习惯。因为简单工厂非常常见,所以掌握这部分也是非常重要的。一种简单工厂的代码示例如下(一个Head First中关于Pizza的例子):
public class SimpleFactory {
public Pizza create(String type) {
Pizza p = null;
if (type.equals("cheese")) p = new CheesePizza();
return p;
}
}
public abstract class Pizza {
// something
}
public class CheesePizza extends Pizza {
// something
}
public class PizzaStore {
SimpleFactory sf = new SimpleFactory();
public Pizza orderPizza(String type) {
Pizza p = null;
p = sf.create(type);
// do something
return p;
}
}
有的时候,把全部的实现都放在工厂里并不是一个好的选择,因为这样失去了一定的弹性,因此我们可以把PizzaStore
中的简单工厂替换掉,允许子类做决定。下面是一个例子:
public abstract class PizzaStore {
public Pizza orderPizza(String type) {
Pizza p = null;
p = createPizza(type);
p.prepare();
p.bake();
p.cut();
p.box();
return p;
}
protected abstract Pizza createPizza(String type);
}
好处是各种继承PizzaStore
的商店可以自行决定如何提供什么样的Pizza。一种工厂方法的范式如下:
abstract Product factoryMethod(String type)
工厂模式的类图如下:
可以发现PizzaStore的具体行为,实际上是通过Pizza的具体种类决定的,同时而且无需知道Pizza的具体种类,也就是说,PizzaStore和各种Pizza的子类通过Pizza这个抽象解耦合,通过这种方式,PizzaStore减少了对具体Pizza类的依赖,具体Pizza类也在依赖相对高层的Pizza抽象。因此在此提出了著名的“依赖倒置”原则。
一些指导方针有助于尽可能少的违反依赖倒置原则:
当然,不必完全遵守,尽可能遵守即可。
抽象工厂:提供一个接口,用于创建相关或者依赖对象的家族,而无需明确指定具体类。(在具体工厂上更进一步进行抽象)