文章目录
核心思想
- 封装变化
- 设计模式往往可以让应用的设计变得简单且有弹性
- 模式是工具而不是规则,可以适当调整以符合实际需求
- 将注意力集中在设计本身,而不是模式上,只有真正需要时才使用模式。有时候简单的方法行得通,特别是在不需要弹性的时候,就别用设计模式
设计原则
- 找出应用中可能需要变化之处,把他们独立出来,不要和那些不需要变化的代码混在一起
- 针对接口编程,而不是针对实现编程
- 多用组合,少用继承
- 为了交互对象之间的松耦合设计而努力
- 开放-关闭原则:类应该对扩展开放,对修改关闭
- 依赖倒置原则(Dependency Inversion):要依赖抽象,不要依赖具体类
- 最少知识原则:减少对象之间的交互,只和你的密友谈话。如果某对象是调用其他方法的返回结果,不要调用该对象的方法
- 好莱坞原则:don’t call us,we will call you(低层不要调用高层,子类不要调用父类),典型模式:模板方法模式
- 单一责任:一个类应该只有一个引起变化的原因 ---- 迭代器模式
设计模式
策略模式
定义:定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户 ----- 封装算法
模板方法模式
定义:在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。非常常用的模式,特别是在创建框架的时候 ----- 封装算法,由子类去提供完整实现
实例:Arrays.sort(),JFrame的paint()和Applet
和策略模式的区别:策略模式选择的组合对象实现了整个算法,而模板方法的算法是在模板方法里定义的;策略模式是使用组合实现的而模板方法是使用继承实现的
观察者模式
定义:定义了对象之间一对多多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新
特点:实现了主题和对象之间的松耦合
实例:Swing GUI组件
装饰者模式
定义:动态地将责任附加到对象上,若要扩展功能,装饰者提供了比继承更有弹性的替代方案
实例:Java IO类
工厂方法模式
定义:定义了一个创建对象的接口(Creator),但由该接口的子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类,选择了哪个子类,就决定了实际创建的产品是什么,子类并不具有在运行时决定生成哪种产品的能力。工厂方法模式比起简单工厂模式的好处是,它让产品的“实现”从“使用”中解耦,如果增加产品或改变产品的实现,Creator并不会受到影响 ------- 封装对象的创建
抽象工厂模式
定义:提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。接口内每个方法都负责创建一个具体产品,抽象工厂的方法常常以工厂方法的方式实现 ------- 封装对象的创建
工厂方法和抽象工厂的区别:二者都是负责创建对象,但工厂方法用的是继承而抽象工厂用的是组合;工厂方法用于创建种产品而抽象工厂用于创建一种产品家族
单例模式
定义:确保一个类只有一个实例,并提供一个全局访问点
实例:Servlet
命令模式
定义:将请求封装成对象,以便使用不同的请求、队列或日志来参数化对象。命令模式也支持撤销操作 ----- 封装调用
实例:CloudStack的command
适配器模式
定义:将一个类的接口转换成客户期望的另一个接口。适配器让原本不兼容的类可以无缝合作。有两种适配器模式,类适配器和对象适配器,类适配器使用继承的方式而对象适配器使用组合的方式
和装饰者模式的区别是:装饰者让自己看起来像被装饰者,而适配器是为了让自己看起来不像被适配者
外观模式
定义:提供一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用
和适配器的区别:适配器的意图是改变接口符合客户的期望,而外观模式的意图是提供子系统的一个简化接口
迭代器模式
定义:提供一种方法顺序访问一个集合对象中的各个元素,而又不暴露其内部表示 ----- 封装遍历
实例:Java集合
组合模式
定义:允许你将对象组合成树形结构来表现“整体/部分”层次结构。组合能让客户以一致的方式处理个别对象以及对象组合。使用组合模式,我们能把相同的操作应用在组合和个别对象上。在大多数情况下,我们可以忽略组合和个别对象之间差别。 ----- 封装组合和个别对象的差别
实例:CloudStack的订阅树
状态模式
定义:允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类 ----封装了条件判断
和策略模式的异同:实现上和策略模式是一样的,都是通过组合来将行为委托给不同的对象,区别在于它们的意图,状态模式内部的状态是随着时间的流逝改变的,而策略模式通常是客户主动指定所要组合的对象是哪个。一般来说,策略模式是除了继承之外的一种弹性替代方案,而状态模式是许多条件判断的替代方案
代理模式
定义:为另一个对象提供一个替身或占位符以控制对这个对象的访问,可以保护对象避免不想要的访问,也可以避免在加载大对象的时候挂起或者隐藏主题在远程运行的事实。被代理的对象可以是远程对象、创建开销大的对象或需要安全控制的对象
代理模式和装饰者模式有点像,二者的区别主要是意图不同,装饰者的意图是为被装饰者增加行为,而代理的意图是控制对象的访问
复合模式
定义:结合两个或以上的模式,组成一个解决方案,解决一再发生的一般性问题
实例:MVC模式
模型利用“观察者”让控制器和视图可以随最新的状态改变而更新;视图和控制器使用了策略模式,控制器是视图的行为,可以随时替换;视图内部使用组合模式来管理窗口、按钮以及其他显示组件;使用适配器将模型适配成符合现有视图和控制器的需要的模型
在B/S架构中,视图是HTML页面,从而不再是模型的观察者,模型的状态更新也不会实时地更新到页面,控制器依然是模型的观察者,只有页面刷新时视图的状态才会被更新;
控制器将来自视图的动作转成模型上的动作,但它不会实现应用逻辑,那是模型做的事,应用逻辑指的是管理与操纵模型中的数据的代码
视图一般不会直接设置模型的状态,而是通过控制器进行,但它可能会持有模型的引用来访问模型的状态,换句话说,视图有模型的只读权限
具体实现
工厂方法模式
- 披萨抽象类
Pizza是一个抽象类,具体的披萨都由这个抽象类派生:
public abstract class Pizza {
String name;
String dough;
String sauce;
ArrayList<String> toppings = new ArrayList<String>();
void prepare() {
System.out.println("Prepare " + name);
System.out.println("Tossing dough...");
System.out.println("Adding sauce...");
System.out.println("Adding toppings: ");
for (String topping : toppings) {
System.out.println(" " + topping);
}
}
void bake() {
System.out.println("Bake for 25 minutes at 350");
}
void cut() {
System.out.println("Cut the pizza into diagonal slices");
}
void box() {
System.out.println("Place pizza in official PizzaStore box");
}
public String getName() {
return name;
}
public String toString() {
StringBuffer display = new StringBuffer();
display.append("---- " + name + " ----\n");
display.append(dough + "\n");
display.append(sauce + "\n");
for (String topping : toppings) {
display.append(topping + "\n");
}
return display.toString();
}
}
- 具体披萨类
NYStyleCheesePizza
NYStyleClamPizza
NYStylePepperoniPizza
NYStyleVeggiePizza
ChicagoStyleCheesePizza
ChicagoStyleClamPizza
ChicagoStylePepperoniPizza
ChicagoStyleVeggiePizza
//这里就提供其中一个的具体实现代码,其他的可以类推
public class ChicagoStyleVeggiePizza extends Pizza {
public ChicagoStyleVeggiePizza() {
name = "Chicago Deep Dish Veggie Pizza";
dough = "Extra Thick Crust Dough";
sauce = "Plum Tomato Sauce";
toppings.add("Shredded Mozzarella Cheese");
toppings.add("Black Olives");
toppings.add("Spinach");
toppings.add("Eggplant");
}
void cut() {
System.out.println("Cutting the pizza into square slices");
}
}
- 工厂接口
public abstract class PizzaStore {
abstract Pizza createPizza(String item);
public Pizza orderPizza(String type) {
Pizza pizza = createPizza(type);
System.out.println("--- Making a " + pizza.getName() + " ---");
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}
- 具体工厂类
ChicagoPizzaStore
NYPizzaStore
//其中一个工厂类的代码
public class NYPizzaStore extends PizzaStore {
Pizza createPizza(String item) {
if (item.equals("cheese")) {
return new NYStyleCheesePizza();
} else if (item.equals("veggie")) {
return new NYStyleVeggiePizza();
} else if (item.equals("clam")) {
return new NYStyleClamPizza();
} else if (item.equals("pepperoni")) {
return new NYStylePepperoniPizza();
} else return null;
}
}
- 披萨店的运作
public class PizzaTestDrive {
public static void main(String[] args) {
PizzaStore nyStore = new NYPizzaStore();
PizzaStore chicagoStore = new ChicagoPizzaStore();
Pizza pizza = nyStore.orderPizza("cheese");
System.out.println("Ethan ordered a " + pizza.getName() + "\n");
pizza = chicagoStore.orderPizza("cheese");
System.out.println("Joel ordered a " + pizza.getName() + "\n");
pizza = nyStore.orderPizza("clam");
System.out.println("Ethan ordered a " + pizza.getName() + "\n");
pizza = chicagoStore.orderPizza("clam");
System.out.println("Joel ordered a " + pizza.getName() + "\n");
pizza = nyStore.orderPizza("pepperoni");
System.out.println("Ethan ordered a " + pizza.getName() + "\n");
pizza = chicagoStore.orderPizza("pepperoni");
System.out.println("Joel ordered a " + pizza.getName() + "\n");
pizza = nyStore.orderPizza("veggie");
System.out.println("Ethan ordered a " + pizza.getName() + "\n");
pizza = chicagoStore.orderPizza("veggie");
System.out.println("Joel ordered a " + pizza.getName() + "\n");
}
}
抽象工厂方法模式
- 披萨抽象类
public abstract class Pizza {
String name;
Dough dough;
Sauce sauce;
Veggies veggies[];
Cheese cheese;
Pepperoni pepperoni;
Clams clam;
abstract void prepare();
void bake() {
System.out.println("Bake for 25 minutes at 350");
}
void cut() {
System.out.println("Cutting the pizza into diagonal slices");
}
void box() {
System.out.println("Place pizza in official PizzaStore box");
}
void setName(String name) {
this.name = name;
}
String getName() {
return name;
}
public String toString() {
StringBuffer result = new StringBuffer();
result.append("---- " + name + " ----\n");
if (dough != null) {
result.append(dough);
result.append("\n");
}
if (sauce != null) {
result.append(sauce);
result.append("\n");
}
if (cheese != null) {
result.append(cheese);
result.append("\n");
}
if (veggies != null) {
for (int i = 0; i < veggies.length; i++) {
result.append(veggies[i]);
if (i < veggies.length-1) {
result.append(", ");
}
}
result.append("\n");
}
if (clam != null) {
result.append(clam);
result.append("\n");
}
if (pepperoni != null) {
result.append(pepperoni);
result.append("\n");
}
return result.toString();
}
}
- 具体披萨类
CheesePizza
ClamPizza
PepperoniPizza
VeggiePizza
public class CheesePizza extends Pizza {
PizzaIngredientFactory ingredientFactory;
public CheesePizza(PizzaIngredientFactory ingredientFactory) {
this.ingredientFactory = ingredientFactory;
}
void prepare() {
System.out.println("Preparing " + name);
dough = ingredientFactory.createDough();
sauce = ingredientFactory.createSauce();
cheese = ingredientFactory.createCheese();
}
}