设计模式笔记1

前言:

  1. 了解OO并不一定能设计出好的系统,设计模式实际上是一些构建OO系统的隐藏经验,可以在构建系统时提供一个大致的思路。所以,要辩证的看设计模式,不能迷信,也不能不信。

  2. 本文使用的开发语言为java,只涉及设计模式的基本思想,并不深究java的语法和设计。

本文主要介绍:策略模式,观察者模式,装饰模式以及工厂模式。

策略模式

策略模式定义了算法族,分别封装起来,让他们之间可以互相替换,此模式可以让算法的变化独立于使用算法的客户。

注意:

  • 区分is-a(继承),has-a(组合:使用多个类)以及实现(implements)
  • 多用组合,少用继承,优点是不仅可以将算法聚合成类,还可以在运行时动态改变行为。
  • 如《Head First》所说,面向接口编程实际上指的是面向超类型编程,这里的接口不单单指Java中的interface,关键在于利用多态对超类型编程,更具体来说,声明一个类的时候不必理会以后执行时的真正类型。

总的来说,就是尽可能分离出is-a,has-a,has-a尽可能通过接口或者抽象类实现,避免通过继承实现导致不能cover住整体的调整。

而且可以通过组合和委托来实现运行时动态扩展的效果。

(我知道自己这段写的不像人话,水平所限,暂时没啥好的表述。。。)

观察者模式

在对象之间定义一种一对多的依赖,这样当一个对象改变状态,依赖他的对象都会收到通知,并自动更新。

直观来说,就是一种发布订阅模式,不过到底是pull还是push不确定。一个典型的观察者模式是一个发布者对应多个订阅者,发布者的某些状态改变后,向订阅者发送通知,同步变化。

具体实现上,可以自己手写也可以通过java.util.Observer和Observable实现,当然在java9之后的版本中Observer相关的实现被废弃了,详细原因有很多,可自行百度。针对这种情况,java包也提供了相应的替代方法,例如java.beans.PropertyChangeEvent以及java.util.concurrent.Flow等。

装饰者模式

一个关键的设计原则是:类应该对扩展开放,对修改关闭。 也叫做开放-关闭原则。装饰者模式中这种原则表现的非常明显,实际上,这种思想在策略模式以及观察者模式中也有一定体现。

直观理解:装饰者模式也可以形象地理解为“套娃模式”,需要一层层的剥开,每一层就是一个装饰器,这样可以在尽可能不影响类实现的基础上扩展功能。

关键要点:

  1. +装饰者和被装饰者都继承自一个超类;
  2. +装饰者需要在实现时实例化一个组件,并包含在装饰者内部;
  3. -装饰者模式会不可避免的带来一些小类,很难快速了解整体设计模式思路。

工厂模式

与其说是一种设计模式,常见的简单工厂更像一个编程习惯。因为简单工厂非常常见,所以掌握这部分也是非常重要的。一种简单工厂的代码示例如下(一个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)

工厂模式的类图如下:

继承
继承
多元关联
Creator
+factoryMethod()
+OneOperation()
Product
ConcreteCreator
+factoryMethod()
ConcreteProduct

可以发现PizzaStore的具体行为,实际上是通过Pizza的具体种类决定的,同时而且无需知道Pizza的具体种类,也就是说,PizzaStore和各种Pizza的子类通过Pizza这个抽象解耦合,通过这种方式,PizzaStore减少了对具体Pizza类的依赖,具体Pizza类也在依赖相对高层的Pizza抽象。因此在此提出了著名的“依赖倒置”原则。

一些指导方针有助于尽可能少的违反依赖倒置原则:

  • 变量不可以持有具体类的引用;(说人话,不要在类里使用new,new工厂除外)
  • 不要让类派生自具体类;(就是所有的类要派生自抽象类或者接口)
  • 不要覆盖基类中实现的方法。(如果非要这样,那么这个基类的抽象就是失败的,基类中的方法应该是由子类共享的)

当然,不必完全遵守,尽可能遵守即可。

抽象工厂:提供一个接口,用于创建相关或者依赖对象的家族,而无需明确指定具体类。(在具体工厂上更进一步进行抽象)

你可能感兴趣的:(设计模式,策略模式,java)