设计模式概述
- 设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。
- 设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。
- 设计模式是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。
- 设计模式不是一种方法和技术,而是一种思想。
- 设计模式和具体的语言无关,学习设计模式就是要建立面向对象的思想,尽可能的面向接口编程,低耦合,高内聚,使设计的程序可复用。
- 学习设计模式能够促进对面向对象思想的理解,反之亦然。它们相辅相成。
设计模式的类型
设计模式按照功能分为三类23种:
- 创建型(5种) : 工厂模式、抽象工厂模式、单例模式、原型模式、构建者模式
- 结构型(7种): 适配器模式、装饰模式、代理模式、外观模式、桥接模式、组合模式、享元模式
- 行为型(11种): 模板方法模式、策略模式、观察者模式、中介者模式、状态模式、责任链模式、命令模式、迭代器模式、访问者模式、解释器模式、备忘录模式
创建型设计模式
step1 简单工厂模式(不属于23种设计模式)
介绍
工厂类拥有一个工厂方法(create),接受了一个参数,通过不同的参数实例化不同的产品类,(spring管理bean用例优化的简单工厂模式)。
图示
优缺点
优点:
- 很明显,简单工厂的特点就是“简单粗暴”,通过一个含参的工厂方法,我们可以实例化任何产品类,上至飞机火箭,下至土豆面条,无所不能。
- 所以简单工厂有一个别名:上帝类。
缺点:
- 任何”东西“的子类都可以被生产,负担太重。当所要生产产品种类非常多时,工厂方法的代码量可能会很庞大。
- 在遵循开闭原则(对拓展开放,对修改关闭)的条件下,简单工厂对于增加新的产品,无能为力。因为增加新产品只能通过修改工厂方法来实现。
工厂方法正好可以解决简单工厂的这两个缺点。
示例
普通-简单工厂类:
public class AnimalFactory {
//简单工厂设计模式(负担太重、不符合开闭原则)
public static Animal createAnimal(String name){
if ("cat".equals(name)) {
return new Cat();
}else if ("dog".equals(name)) {
return new Dog();
}else if ("cow".equals(name)) {
return new Dog();
}else{
return null;
}
}
}
静态方法工厂:
//该简单工厂,也称为静态方法工厂
public class AnimalFactory2 {
public static Dog createDog(){
return new Dog();
}
public static Cat createCat(){
return new Cat();
}
}
step2 工厂方法模式
介绍
工厂方法是针对每一种产品提供一个工厂类。
通过不同的工厂实例来创建不同的产品实例。
图示
优缺点
优点:
- 工厂方法模式就很好的减轻了工厂类的负担,把某一类/某一种东西交由一个工厂生产;(对应简单工厂的缺点1)
- 同时增加某一类”东西“并不需要修改工厂类,只需要添加生产这类”东西“的工厂即可,使得工厂类符合开放-封闭原则。
缺点:
- 对于某些可以形成产品族(一组产品)的情况处理比较复杂。
示例
- 抽象出来的工厂对象
// 抽象出来的动物工厂----它只负责生产一种产品
public abstract class AnimalFactory {
// 工厂方法
public abstract Animal createAnimal();
}
- 具体的工厂对象1
// 具体的工厂实现类
public class CatFactory extends AnimalFactory {
@Override
public Animal createAnimal() {
return new Cat();
}
}
- 具体的工厂对象2
//具体的工厂实现类
public class DogFactory extends AnimalFactory {
@Override
public Animal createAnimal() {
return new Dog();
}
}
step3 抽象工厂模式
介绍
- 抽象工厂是应对产品族概念的。
- 上边的工厂方法模式是一种极端情况的抽象工厂模式(即只生产一种产品的抽象工厂模式),而抽象工厂模式可以看成是工厂方法模式的一种推广。
图示
工厂模式区别
- 简单工厂 : 使用一个工厂对象用来生产同一等级结构中的任意产品。(不支持拓展增加产品)
- 工厂方法 : 使用多个工厂对象用来生产同一等级结构中对应的固定产品。(支持拓展增加产品)
- 抽象工厂 : 使用多个工厂对象用来生产不同产品族的全部产品。(不支持拓展增加产品;支持增加产品族)
step4 原型模式
原型模式虽然是创建型的模式,但是与工厂模式没有关系,从名字即可看出,该模式的思想就是将一个对象作
为原型,对其进行复制、克隆,产生一个和原对象类似的新对象。
- 先创建一个原型类:
public class Prototype implements Cloneable {
public Object clone() throws CloneNotSupportedException {
Prototype proto = (Prototype) super.clone();
return proto;
}
}
很简单,一个原型类,只需要实现Cloneable接口,覆写clone方法,此处clone方法可以改成任意的名称,因为Cloneable接口是个空接口,你可以任意定义实现类的方法名,如cloneA或者cloneB,因为此处的重点是super.clone()这句话,super.clone()调用的是Object的clone()方法,而在Object类中,clone()是native的,具体怎么实现,此处不再深究。
在这儿,我将结合对象的浅复制和深复制来说一下,首先需要了解对象深、浅复制的概念:
- 浅复制:将一个对象复制后,基本数据类型的变量都会重新创建,而引用类型,指向的还是原对象所指向的。
- 深复制:将一个对象复制后,不论是基本数据类型还有引用类型,都是重新创建的。简单来说,就是深复制进行了完全彻底的复制,而浅复制不彻底。
写一个深浅复制的例子
public class Prototype implements Cloneable, Serializable {
private static final long serialVersionUID = 1L;
private String string;
private SerializableObject obj;
/* 浅复制 */
public Object clone() throws CloneNotSupportedException {
Prototype proto = (Prototype) super.clone();
return proto;
}
/* 深复制 */
public Object deepClone() throws IOException, ClassNotFoundException {
/* 写入当前对象的二进制流 */
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
/* 读出二进制流产生的新对象 */
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return ois.readObject();
}
public String getString() {
return string;
}
public void setString(String string) {
this.string = string;
}
public SerializableObject getObj() {
return obj;
}
public void setObj(SerializableObject obj) {
this.obj = obj;
}
}
class SerializableObject implements Serializable {
private static final long serialVersionUID = 1L;
}
step5 构建者模式(建造者模式)
建造者模式的定义是:将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示,这样的设计模式被称为建造者模式。
建造者模式的角色定义,在建造者模式中存在以下4个角色:
- 1. builder:为创建一个产品对象的各个部件指定抽象接口。
- 2. ConcreteBuilder:实现Builder的接口以构造和装配该产品的各个部件,定义并明确它所创建的表示,并提供一个检索产品的接口。
- 3. Director:构造一个使用Builder接口的对象。
- 4. Product:表示被构造的复杂对象。ConcreteBuilder创建该产品的内部表示并定义它的装配过程,包含定义组成部件的类,包括将这些部件装配成最终产品的接口。
工厂模式和构建者模式的区别
- 构建者模式和工厂模式很类似,区别在于构建者模式是一种个性化产品的创建。而工厂模式是一种标准化的产品创建。
- 导演类:按照一定的顺序或者一定的需求去组装一个产品。
- 构造者类:提供对产品的不同个性化定制,最终创建出产品。
- 产品类:最终的产品
构建者:
// 构建器
public class StudentBuilder {
// 需要构建的对象
private Student student = new Student();
public StudentBuilder id(int id) {
student.setId(id);
return this;
}
public StudentBuilder name(String name) {
student.setName(name);
return this;
}
public StudentBuilder age(int age) {
student.setAge(age);
return this;
}
public StudentBuilder father(String fatherName) {
Father father = new Father();
father.setName(fatherName);
student.setFather(father);
return this;
}
// 构建对象
public Student build() {
return student;
}
}
导演类:
// 导演类/测试类
public class BuildDemo {
public static void main(String[] args) {
StudentBuilder builder = new StudentBuilder();
// 决定如何创建一个Student
Student student = builder.age(1).name("zhangsan").father("zhaosi").build();
System.out.println(student);
}
}