设计模式 Design Patterns
设计模式的基础:抽象,封装,多态,继承
良好的OO设计必须具备:可复用、可扩充、可维护三个特性
OO原则
- 合成/聚合复用原则:封装变化,多用组合,减少继承
- 针对接口编程,不针对实现编程
- 为交互对象之间的松耦合设计而努力
- 开放封闭原则:对扩展开放,对修改关闭
- 依赖倒置原则:依赖抽象不要依赖具体类
- 最少知识原则:一个对象应该对其他对象保持最少的了解
- 好莱坞原则:Don‘ t call us, we’ ll call you
- 单一责任原则:一个类应该只有一个引起变化的原因
类之间的关系:IS-A, HAS-A, IMPLEMENTS
策略模式 Strategy Pattern
定义
定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
代码示例
public abstract class Duck{
FlyBehavior flyBehavior;
QuackBehavior quackBehavior;
public Duck(){
}
pulbic void setFlyBehavior(FlyBehavior fb){
flyBehavior = fb;}
pulbic void setQuackBehavior(QuackBehavior qb){
quackBehavior = qb;}
public abstract void display();
public void performFly(){
flyBehavior.fly();
}
public void performQuack(){
quackBehavior.quack();
}
}
鸭子所做的一组行为,即一族算法,可以利用set方法被替换,这种方法就是组合,将两个类结合起来使用,使用组合建立系统具有很大的弹性,可以在运行时动态地改变行为。
主要解决问题
解决算法行为类似时,过多if…else…问题。
解决途径
共同实现一个接口,将算法封装成类,需要时进行替换。
观察者模式 Observer Pattern
定义
在对象之间定义了一对多的依赖,这样依赖,当一个对象改变状态,依赖他的对象都会收到通知并自动更新。
代码示例
public class WeatherData extends Observable{
private float temperature;
private float pressure;
public void measurementsChanged(){
setChanged();
notifyObservers();
}
public void setMeasurements(float temperature,float pressure){
this.temperature = temperature;
this.pressure = pressure;
measurementsChanged();
}
public float getTemperature(){
...};
public float getPressure(){
...};
}
public class ConditionDisplay implements Observer{
Observable observable;
private float temperature;
private float pressure;
public ConditionDisplay(Observable ob){
this.observable = ob;
observable.addObserver(this);
}
public void update(Observable obs, Object arg){
if(obs instanceof WeatherData){
WeatherData wd = (WeatherData) obs;
this.temperature = wd.getTemperature();
this.pressure = wd.getPressure();
display();
}
}
public void display(){
print(...);
}
}
利用JDK内置支持,首先”主题“继承Observable接口,“观察者”实现Observer接口。在Observable类中,先调用setChange()方法,标记状态改变,在调用notifyObservers()方法,方法中会调用它的观察者的update()方法,其中参数Object arg可决定”推“或”拉“数据。
主要解决问题
一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。
解决途径
实现Observable和Observer接口,通过遍历注册的观察者对象数组,广播通知。
装饰者模式 Decorator Pattern
定义
动态地将责任附加到对象上,若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
代码示例
public abstrack class Beverage{
String description = "Unknown Beverage";
public String get Description(){
return description;
}
public abstract double cost();
}
pulbic abstract class CondimentDecorator extends Beverage{
public abstract String get Description();
}
public class Espresso extends Beverage{
public Espresso(){
description = "Espresso";
}
public double cost(){
return 1.99;
}
}
public class HouseBlend extends Beverage{
public HouseBlend(){
description = "HouseBlend";
}
public double cost(){
return 0.89;
}
}
public class Mocha extends CondimentDecorator{
Beverage beverage;
public Mocha(Beverage beverage){
this.beverage = beverage;
}
pulbic String getDescription(){
return beverage.getDescription() + ", Mocha";
}
public double cost(){
return 0.2 + beverage.cost();
}
}
puvlic class CoffeeHouse{
public static void main(String args[]){
Beverage beverage = new Espresso();
Beverage decoratedBeverage = new Mocha(beverage);
print(decoratedBeverage.getDescription() + "$" +decoratedBeverage.cost());
}
}
保持类方法签名完整性的前提下,利用继承提供了额外的功能。我们需要有抽象组件(Beverage),具体组件(Espresso,HouseBlend),抽象装饰者(CondimentDecorator)以及具体修饰者(Mocha)。继承或实现接口的目的不是为了获得行为而是获得相同的类型。
主要解决问题
防止单纯继承导致的子类膨胀问题。
解决途径
通过继承和组合扩展父类。实现了对扩展开放对修改关闭。
工厂模式 Factory Pattern
定义
工厂模式是Java中最常用的设计模式之一
简单工厂:不是工厂模式,只是OO编程习惯。
工厂方法模式: 定义了一个创建对象的接口,但由于子类决定要求实例化的类时哪一个。工厂方法让类把实例化推迟到子类。
抽象工厂模式: 提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。
代码示例
简单工厂
public class SimplePizzaFactory{
public Pizza createPizza(String type){
Pizza pizza = nul;
if(type.equals("cheese")){
pizza = new CheesePizza();
}else if(type.equals("pepperoni")){
pizza = new PepperoniPizza();
}
return pizza;
}
}
public class PizzaStore{
SimplePizzaFactory factory;
public PizzaStore(SimplePizzaFactory factory){
this.factory = factory;
}
public Pizza orderPizza(String type){
Pizza pizza;
pizza = factory.createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}
简单工厂利用组合,通过接收的参数不同返回不同的对象负责具体类的实例化,但是又缺点拓展性差,不符合开闭原则,不修改代码就无法拓展。
工厂方法模式
public abstract class PizzaStore{
public Pizza orderPizza(String type){
Pizza pizza;
pizza = createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
protected abstract Pizza createPizza(String type);
}
public class NyPizzaStore extends PizzaStore{
Pizza createPizza(String item){
if(item.equals("cheese")){
return new NYStyleCheesePizza();
}else if(item.equals("pepperoni")){
return new NYStylePepperoniPizza();
}else return null;
}
}
工厂方法模式中,PizzaStore称为创建者类,其将实例化责任转移到一个方法中即createPizza(String),这样可以将处理对象的行为交给子类负责,超类代码和子类对象常见代码解耦,同时拓展性增强,支持增加新工厂产品。
抽象工厂模式
public interface PizzaIngredientFactory{
public Dough createDough();
public Cheese createCheese();
}
public class NYPizzaIngredientFactory implements PizzaIngredientFactory{
public Dough createDough(){
return new ThinCrustDough();
}
public Cheese createCheese(){
return new ReggianoCheese();
}
}
public abstract class Pizza{
String name;
Dough dough;
Cheese cheese;
abstract void prepare();
void bake(){
print("bake")
}
//cut..box
}
public class CheesPizza extends Pizza{
PizzaIngredientFactory ingredientFactory;
public CheesPizza(PizzaIngredientFactory ingredientFactory){
this.ingredientFactory = ingredientFactory;
}
void prepare(){
print("preparing");
dough = ingredientFactory.createDough();
cheese = ingredientFactory.createCheese();
}
}
引入抽象工厂,工厂方法使用类,而抽象工厂使用对象,通过对象的组合创建一个产品家族。抽象工厂定义了一个负责创建一族产品的接口,接口中每个方法都创建一个具体产品,并用子类实现具体的做法。因此抽象工厂也是利用工厂方法的思想实现的。
区分工厂方法和抽象工厂
工厂方法 | 抽象工厂 | |
---|---|---|
实现原理 | 利用继承 | 利用对象组合 |
扩展能力 | 支持增加新产品 | 支持增加产品族 |
主要解决问题
封装对象的创建。
解决途径
将类的实例化延迟到子类中进行。
单例模式 Singleton Pattern
定义
确保一个类只有一个实例,并提供全局访问点。
代码示例
经典实现
public class Singleton{
private static Singleton uniqueInstance;
private Singleton(){
}
public static Singleton getInstance(){
if(uniqueInstance == null){
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
}
用静态便令记录唯一一个实例,构造器声明为私有,禁止外部类调用构造