设计模式个人总结
设计模式七大原则
- 开闭原则(OCP):一个软件实体(类、模板、方法)应该对扩展开放,对修改关闭
- 单一职责原则(SRP)
- 里式替换原则(LSP)
- 依赖倒置原则(DIP)
- 接口隔离原则(ISP)
- 合成复用原则
- 迪米特法则(LOD)
以上简称为 “SOLID”
七大原则详解
迪米特法则(LOD)
-
定义:
一个软件实体应当尽可能地与其他实体发生相互作用
-
详细概述:
迪米特法则又叫最少知道原则,通俗的来讲,就是一个类对自己依赖的类知道的越少越好。也就是说,对于被依赖的类来说,无论逻辑多么复杂,都尽量的将逻辑封装在类的内部,对外除了提供的public方法,不对外泄露任何信息。
-
问题由来:
类与类之间的关系越密切,耦合度越大,当一个类发生改变时,对令一个类的影响也越大。迪米特法则可降低系统的耦合度,时类与类之间保持松散的耦合关系。
-
其他定义形式:
迪米特法则还有一个英文解释是:talk only to your immediate friends:只与直接的朋友交流。对于一个对象,其朋友包括:成员属性、方法入参中的类对象、方法返回值中的类、如果当前对象的成员对象是一个集合,那么集合中的元素也都是朋友。
设计模式分类
创建型模式:
- 用于描述“怎样创建对象”,他的主要特点是“将对象的创建于使用分离”
- 主要包括 单例模式、工厂方法模式、抽象工厂模式、原型模式、建造者模式 (5种)
结构型模式:
- 用于描述如何将类或对象按某种布局组成更大的结构
- 主要包括 代理模式、适配器模式、桥接模式、装饰模式、外观模式、享元模式、组合模式 (7种)
行为型模式:
- 用于描述类或对象之间怎样相互协作共同完成单个对象无法单独完成的任务,以及怎样分配职责
- 主要包括 模板方法模式、策略模式、命令模式、职责链模式、状态模式、观察者模式、中介者模式、迭代器模式、访问者模式、备忘录模式、解释器模式 (11种)
创建型模式
单例模式
定义
Ensure a class has only one instance, and provide a global point of access to it.(保证一个类只有一个实例,并且提供一个全局访问点)
场景
重量级的对象,不需要多个实例,如线程池、数据库连接池
实现
- 饿汉式 - 方式1(静态变量)
/**
* 饿汉式
* 静态变量创建类的对象
*/
public class Singleton {
//私有构造方法
private Singleton(){}
//在成员位置创建该类的对象
private static Singleton instance = new Singleton();
//对外提供静态方法获取该对象
public static Singleton getInstance(){
return instance;
}
}
- 饿汉式 - 方式2(静态代码块)
/**
* 饿汉式
* 在静态代码块中创建该类的对象
*/
public class Singleton{
//私有构造方法
private Singleton(){}
//在成员位置创建该类的对象
private static Singleton instance;
static {
instance = new Singleton();
}
//对外提供静态方法获取该对象
public static Singleton getInstance() {
return instance;
}
}
- 懒汉式 - 方式1(线程不安全)
/**
* 懒汉式
* 线程不安全
*/
public class Singleton{
//私有构造方法
private Singleton(){}
//在成员位置创建该类的对象
private static Singleton instance;
//对外提供静态方法获取该对象
public static Singleton getInstance(){
if (instance == null){
instance = new Singleton();
}
return instance;
}
}
- 懒汉式 - 方式2(线程安全)
/**
* 懒汉式
* 线程安全
*/
public class Singleton{
//私有构造方法
private Singleton(){}
//在成员位置创建该类的对象
private static Singleton instance;
//对外提供静态方法获取该对象
public static synchronized Singleton getInstance(){
if (instance != null){
instance = new Singleton();
}
return instance;
}
}
- 懒汉式 - 方式3(双重检查锁)
/**
* 懒汉式
* 双重检查方式
*/
public class Singleton{
//私有构造方法
private Singleton(){}
//在成员位置创建该类的对象
//private static Singleton instance;
private static volatile Singleton instance;
//对外提供静态方法获取该对象
public static Singleton getInstance(){
//
if (instance == null){
synchronized (Singleton.class){
if (instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
特别的:添加 volatile
关键字之后的双重检查锁模式是一种比较好的单例实现模式,能够保证在多线程 的情况下线程安全也不会有性能问题。
- 懒汉式 - 方式4(静态内部类方式)
/**
* 懒汉式
* 静态内部类方式
*/
public class Singleton{
//私有构造方法
private Singleton(){}
//静态内部类
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
//对外提供静态方法获取该对象
public static Singleton getInstance(){
return SingletonHolder.INSTANCE;
}
}
- 枚举方式
/**
* 枚举方式
*/
public enum Singleton{
INSTANCE;
}
简单工厂模式
概述
简单工厂模式又称为静态工厂模式,他不属于23种设计模式(因为他不符合开闭等原则),但现实中却经常用到
具体实现为:定义一个工厂类,该类根据传入的参数,动态决定应该创建哪一个产品类(这些产品类继承自一个父类或接口)的实例。其实就是将一个具体类的实例化交给一个类的静态方法来执行,该类被称为工厂类,静态方法被称为静态工厂方法,思想也非常简单。
角色
- 工厂
- 抽象产品
- 具体产品
思想及实现
由工厂根据传入的参数生产具体产品,这些具体产品继承自某个抽象产品。但假如再有新的茶的话,就需要修改工厂的逻辑代码,不符合“开闭原则”。
//工厂
class TeaFactory {
public static Tea getTea(String teaName) throws Exception{
if (teaName.equals("红茶")){
return new RedTea();
}else if (teaName.equals("绿茶")){
return new GreenTea();
}else {
throw new Exception();
}
}
}
//抽象产品
abstract class Tea {
abstract void drink();
abstract void drinkAfter();
}
//具体产品1
class RedTea extends Tea {
public RedTea(){
System.out.println("在制作红茶");
}
@Override
public void drink() {
System.out.println("喝红茶");
}
@Override
public void drinkAfter() {
System.out.println("喝完之后开始收拾");
}
}
//具体产品2
class GreenTea extends Tea {
public GreenTea(){
System.out.println("在制作绿茶");
}
@Override
public void drink() {
System.out.println("喝绿茶");
}
@Override
public void drinkAfter() {
System.out.println("喝完之后开始收拾");
}
}
//生产
public static void main(String[] args) {
try {
//开始制茶
Tea greenTea = TeaFactory.getTea("绿茶");
greenTea.drink();
greenTea.drinkAfter();
} catch (Exception e) {
System.out.println("不会做该茶");
}
模式缺点
- 工厂类集中了所有产品的创建逻辑,工厂类一般被我们称为“全能类”或“上帝类”,因为所有的产品创建它都能完成,但这不一定是好事
- 不利于系统的扩展和维护。从工厂的角度来说简单工厂模式不符合“开闭原则”。简单工厂由于使用了静态工厂方法,造成工厂角色无法形成基于继承的结构等级。
工厂方法模式
概述
工厂方法模式,又称工厂模式、多态工厂模式和虚拟构造器模式,通过定义工厂父类负责定义创建对象的公共接口,而子类则负责生产具体的对象。
工厂方法模式的主要作用是将具体产品类的实例化延迟到工厂的子类(具体工厂)中完成,即由子类来决定应该实例化哪一个类。
角色
- 抽象工厂
- 具体工厂
- 抽象产品
- 具体产品
实现
如果再有其他种类的新茶时,只需要创建该茶的类和相应的工厂即可
//抽象工厂
abstract class TeaFactory{
//定义了返回产品的规范
public abstract Tea getTea();
}
//具体工厂-红茶
class RedTeaFactory extends TeaFactory{
public Tea getTea() {
return new RedTea();
}
}
//具体工厂-绿茶
class GreenTeaFactory extends TeaFactory{
public Tea getTea() {
return new GreenTea();
}
}
//抽象产品
abstract class Tea {
abstract void drink();
abstract void drinkAfter();
}
//红茶-具体产品
class RedTea extends Tea {
public RedTea(){
System.out.println("在制作红茶");
}
@Override
public void drink() {
System.out.println("喝红茶");
}
@Override
public void drinkAfter() {
System.out.println("喝完红茶开始收拾");
}
}
//绿茶-具体产品
class GreenTea extends Tea {
public GreenTea(){
System.out.println("在制作绿茶");
}
@Override
public void drink() {
System.out.println("喝绿茶");
}
@Override
public void drinkAfter() {
System.out.println("喝完绿茶开始收拾");
}
}
public static void main(String[] args) {
//喝绿茶
TeaFactory teaFactory = new GreenTeaFactory();
Tea tea = teaFactory.getTea();
tea.drink();
tea.drinkAfter();
}
优缺点
-
优点
- 用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程;
- 在系统增加新的产品时只需要添加具体产品类和对应的具体工厂类,无须对原工厂进行任何修改, 满足开闭原则;
-
缺点
- 每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,这增加了系统的复杂度
- 一个具体工厂只能创建一种具体产品
总结
工厂模式可以说是简单工厂模式的进一步抽象和扩展,在保留了简单工厂的封装优点的同时,让扩展变得简单,让继承变得可行,增加了多态性的体现。
抽象工厂模式
模式由来
工厂方法模式考虑的是同一类产品,同种类产品称为同等级产品。也就是说,工厂类只考虑生产同类的产品,并不能跨类生产。如果现在有个需求要求手机厂能够生产电视怎么办?此时抽象工厂登场。
概述
抽象工厂模式就是对同一组具有相同主题的工厂进行封装。抽象工厂就是工厂方法模式的升级版本,工厂方法只生产同一类(等级)的产品,而抽象工厂模式可生产多个类(等级)的产品。
产品等级
产品等级指的是不同厂商(工厂)生产的同一类产品,如红茶和绿茶(都是Tea的抽象)
产品族
同一个具体工厂所生产的位于不同类的一组产品成为一个产品族,如手机厂生产的手机、电视、手表等
角色
- 抽象工厂
- 具体工厂
- 抽象产品
- 具体产品
实现
//抽象工厂
abstract class AbstractFactory {
//生产茶
public abstract Tea createTea();
//生产食物
public abstract Food createFood();
}
//红茶工厂,红茶+珍珠果
class RedTeaFactory extends AbstractFactory{
@Override
public Tea createTea() {
return new RedTea();
}
@Override
public Food createFood() {
return new Pear1();
}
}
//绿茶工厂,绿茶+椰果
class GreenTeaFactory extends AbstractFactory{
@Override
public Tea createTea() {
return new GreenTea();
}
@Override
public Food createFood() {
return new Coconut();
}
}
//抽象产品1-茶
abstract class Tea {
public abstract void drink();
}
//红茶
class RedTea extends Tea {
public RedTea(){
System.out.println("在制作红茶");
}
@Override
public void drink() {
System.out.println("女朋友在喝红茶");
}
}
//绿茶
class GreenTea extends Tea {
public GreenTea(){
System.out.println("在制作绿茶");
}
@Override
public void drink() {
System.out.println("女朋友在喝绿茶");
}
}
//抽象产品2-辅料食物
abstract class Food {
public abstract void eat();
}
//珍珠果
class Pear1 extends Food {
public Pear1(){
System.out.println("在制造珍珠果");
}
@Override
public void eat() {
System.out.println("女朋友开始吃珍珠果");
}
}
//椰果
class Coconut extends Food {
public Coconut(){
System.out.println("在制造椰果");
}
@Override
public void eat() {
System.out.println("女朋友开始吃椰果");
}
}
public static void main(String[] args) {
GreenTeaFactory greenTeaFactory = new GreenTeaFactory();
Tea tea = greenTeaFactory.createTea();
Food food = greenTeaFactory.createFood();
tea.drink();
food.eat();
}
优缺点
-
优点
- 当增加一个新的产品族时不需要修改原代码,满足开闭原则
- 当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。
-
缺点
- 当产品族中需要增加一个新的产品时,所有的工厂类都需要进行修改。
原型模式
概念
用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型对象相同的新对象。
分类
原型模式分为 浅克隆 和 深克隆
- 浅克隆:创建一个新对象,新对象的属性和原来对象完全相同(包括非基本类),对于非基本类型属性,仍指向原有属性所指向的对象的内存地址
- 深克隆:创建一个新对象,属性中引用的其他对象也会被客隆,故不再指向原有对象地址
角色
- 抽象原型类
- 具体原型类
- 访问类
实现
Java中的Object类中提供了 clone()
方法来实现浅克隆。
Cloneable
接口就是抽象原型类,而实现了Cloneable
接口的子实现类就是具体原型类,调用实现Cloneable
接口的类的clone()
方法的类即为访问类
//具体原型类
public class Realizetype implements Cloneable {
public Realizetype() {
System.out.println("具体的原型对象创建完成!");
}
@Override
protected Realizetype clone() throws CloneNotSupportedException {
System.out.println("具体原型复制成功!");
return (Realizetype) super.clone();
}
}
//访问类
public class PrototypeTest {
public static void main(String[] args) throws CloneNotSupportedException {
Realizetype real = new Realizetype();
Realizetype clone = r1.clone();
System.out.println("对象r1和r2是同一个对象?" + (real == clone));
}
}
浅克隆与深克隆代码实现见详细文档
建造者模式
概述
角色
实现