工厂模式专门负责实例化有大量公共接口的类。工厂模式可以动态地决定将哪一个类实例化,而不必实现知道每次要实例化哪一个类。客户类和工厂类是分开的。消费者无论什么时候需要某种产品,需要做的只是向工厂提出请求即可。消费者无需修改就可以接纳新产品。当然也存在缺点,就是当产品修改时,工厂类也要做出相应的修改。
工厂模式包含以下几个形态
1)简单工厂模式(Simple Factory)模式。简单工厂模式的工厂类是根据提供给他的参数,返回几个可能产品中的一个类的实例,通常情况下它返回的类都有一个公共的父类和公共的方法。设计类图如图所示:
其中Product为待实例化的基类,它可以有多个子类;SimpleFactory类中提供了实例化Product的方法,这个方法可以根据传入的参数动态地创建出某一个类型产品的对象。
2)工厂方法模式(Factory Method)模式。工厂方法模式是类的创建模式,其用意是定义一个用于创建产品对象的工厂接口,而实际创建工作推迟到工厂接口的子类中。它属于简单工厂模式的进一步抽象和推广。多态的使用,使得工厂方法模式保持了简单工厂模式的优点,而且客服了缺点。设计类图:
Product 为产品的接口或者基类,所有产品都实现这个接口或抽象类,这样就可以在运行时根据需求创建对应的产品类。Creator实现了对产品的所有的操作方法,而不实现产品对象的实例化。产品的实例化由Creator的子类来完成。
3)抽象工厂模式(Abstract Factory)模式。抽象工厂模式是所有形态工厂模式中最为抽象和最具一般性的一种形态。抽象工厂模式是指当有多个抽象角色时使用的一种工厂模式,抽象工厂模式可以向客户端提供一个借口,使客户端在不必指定产品的具体的情况下,创建多个产品族中的产品对象。根据LSP原则,任何接受父类型的地方,都应当能够接受子类型。因此,实际上系统所需要的,仅仅是类型与这些抽象产品角色相同的一些案例,而不是这些抽象产品的实例。换句话说,也就是这些抽象产品的具体子类的实例。工厂类负责创建抽象产品的具体子类的实例。设计类图:
AbstractProductA 和 AbstractProductB 代表一个产品家族,实现这些接口的类代表具体的产品。AbstractFactory为创建产品的接口,能够创建这个产品家族中所有类型的产品,它的子类可以根据具体情况创建对应的产品。
观察者模式(发布/订阅模式)提供了避免组件之间紧耦合的另一种方法,它将观察者和被观察者的对象分开。该模式中,一个对象通过添加一个方法使得本身可以观察。当可观察的对象更改时,它会将消息发送到已注册的观察者。这些观察者收到的消息后所执行的操作与可观察的对象无关,这种观察模式使得对象可以相互对话,而不必了解原因。
Java语言和C#语言的事件处理方式就是采用的这种设计模式。
例如,用户界面可以作为观察者,业务数据是被观察者,当数据有变化后会通知界面,界面收到通知后,会根据自己的显示方式修改页面的显示。面向对象设计的一个原则是:系统中的每一个类将重点放在一个功能上,而不是其他方面。一个对象只做一件事情,并且将它做好。观察者模式在模块之间划定了清晰的界限,提高了应用程序的可维护性和重用性。设计类图:
下面结合一个java代码来理解观察者模式:
package designpattern;
import java.util.ArrayList;
interface Subject {
void registerObserver(Observer o);
void removeObserver(Observer o);
void nofityObservers();
}
class Wether implements Subject {
// 观察者列表
private ArrayList<Observer> observers = new ArrayList<Observer>();
// 温度
private float temperature;
@Override
public void registerObserver(Observer o) {
this.observers.add(o);
}
@Override
public void removeObserver(Observer o) {
this.observers.remove(o);
}
@Override
public void nofityObservers() {
for (int i = 0; i < this.observers.size(); i++) {
this.observers.get(i).upate(temperature);
}
}
public void weatherChange() {
this.nofityObservers();
}
public float getTemperature() {
return temperature;
}
public void setTemperature(float temperature) {
this.temperature = temperature;
nofityObservers();
}
}
interface Observer {
void upate(float temp);
}
class WetherDisplay1 implements Observer {
private float temprature;
public WetherDisplay1(Subject wether) {
wether.registerObserver(this);
}
@Override
public void upate(float temp) {
this.temprature = temp;
display();
}
public void display() {
System.out.println("display1****:" + this.temprature);
}
}
class WetherDisplay2 implements Observer {
private float temprature;
public WetherDisplay2(Subject wether) {
wether.registerObserver(this);
}
@Override
public void upate(float temp) {
this.temprature = temp;
this.display();
}
public void display() {
System.out.println("display2----:" + this.temprature);
}
}
public class OvserverTest {
public static void main(String[] args) {
Wether wether = new Wether();
WetherDisplay1 d1 = new WetherDisplay1(wether);
WetherDisplay2 d2 = new WetherDisplay2(wether);
wether.setTemperature(27);
wether.setTemperature(26);
}
}
运行结果:
适配器模式也称变压器模式,它是把一个类的接口转换成客户端所期望的另一个接口,从而使原本因接口不匹配而无法一起工作的两个类能够一起工作。适配器类可以根据所传递的参数返回一个合适的实例给客户端。
适配器模式主要应用于“希望通过一些现存的类,但是接口又与复用环境要求不一致的情况”,在遗留代码复用,类库迁移等方面非常有用。同时适配器模式有对象适配器和类适配器两种形式的实现结构,但是类结构适配器采用“多继承”的实现方式,会引起程序的高耦合,所以一般不推荐使用,而对象适配器采用“对象组合”的方式,耦合度低,应用范围更广。
单例模式
在这里直接通过两个代码来演示一下单例模式:
首先看下面两个单例模式的写法:
写法一:
package designpattern;
class SinglePatternTest1 {
private static SinglePatternTest1 test = new SinglePatternTest1();
public SinglePatternTest1() {
}
public static SinglePatternTest1 getInstance() {
return test;
}
}
写法二:
package designpattern;
public class SignalPatternTest2 {
private static SignalPatternTest2 test = null;
public SignalPatternTest2() {
}
public static SignalPatternTest2 getInstance() {
if (test == null) {
test = new SignalPatternTest2();
}
return test;
}
}
对于第一种,当类被加载的时候,已经创建好了一个静态对象,因此,是线程安全的,但是缺点在于还没有被使用的时候,就已经被创建出来了。
对于第二种,缺点如下:这种写法不是线程安全的,原因在于当第一个线程执行判断,第二个线程也执行按断语句,接着会执行test=new SignalPatternTest2()这样,在多线程环境下,就有可能会创建两个对象。当然这种写法的有点在于按需创建对象,只有对象被使用的时候才会被创建。
下面,介绍在多线程环境下的单例模式,同样的,这里我们也有两种写法,来进行比较一下:
package designpattern;
public class Singleton1 {
private static Singleton1 instance;
private Singleton1() {
}
public static synchronized Singleton1 getInstance() {
if (instance == null) {
instance = new Singleton1();
}
return instance;
}
}
这种写法是线程安全的,但是每次调用的时候都需要进行同步这样会降低效率。
再看另一种写法:
package designpattern;
import chap1.Singleton;
public class Singleton2 {
private volatile static Singleton2 singleton;
private Singleton2() {
}
public static Singleton2 getInstance() {
if (singleton == null) {
synchronized (Singleton2.class) {
if (singleton == null) {
singleton = new Singleton2();
}
}
}
return singleton;
}
}
这种写法首先会判断singleton是否为空,这一对象一旦被创建也就不会继续后面的同步代码,这样,会更加有效率。
珍爱生命,拒绝码农。