软件设计模式

HeadFirst设计模式笔记整理(持续更新)


第一章

原则1:封装变化

封装变化原则
把会变化的部分取出并封装起来,以便以后可以轻易地改动或扩充此部分,而不影响
不需要变化的其他部分

原则2:面向接口

针对接口编程
将某些行为或方法放在分开的类中,此类专门提供某行为接口的实现。

原则3:组合

![在这里插入图片描述](https://img-blog.csdnimg.cn/20190211112533148.jpg
在这里插入图片描述
![多用组合](https://img-blog.csdnimg.cn/20190210130759775.png
不采用继承,而是将几个类组合起来用。使用组合建立的系统具有较大地弹性,不仅可以将算法族封装成类,更可以在运行时动态的改变行为,只要组合的行为对象符合正确的接口标准。

模式一:策略模式

场景:业务需要,系统对象中有一部分属性或方法会经常变动。如不同英雄可以使用不同的武器,那么他的攻击方法将会动态变化。

定义:将某些常变化的行为封装成算法族,使他们实现同一个接口,然后将该接口类型作为抽象出的很少变化的基类的成员变量,进行组合,使算法的变化独立于使用算法的客户。
示例:
在这里插入图片描述
图中有继承自Character抽象类的不同的角色,可以使用不同的武器;不同武器的不同行为被封装成了实现WeaponBehavior接口的不同类(算法族);通过调用setWeapon()方法可以动态的切换武器。


第二章

原则4:松耦合

松耦合原则
典例:MVC

模式二:观察者模式

场景:多个不同的对象引用同一个对象(主题对象)的某些属性,当其属性发生变化需相应改变所有引用它的对象。如气象站数据中心数据发生变化,各不同类型的布告板需相应更新显示。

定义:以一种松耦合的方式,定义对象之间的一对多依赖,当一个对象(主题)改变状态时,它的所有依赖者(观察者)都会收到通知并自动更新。
典例:JavaBeans、Swing。
在这里插入图片描述
示例:气象系统设计
在这里插入图片描述
使用java.util.Observable实现气象站
WeatherData类:

import java.util.Observable;
	
public class WeatherData extends Observable {
	private float temperature;
	private float humidity;
	private float pressure;
	
	public WeatherData() { }
	
	public void measurementsChanged() {
		//调用setChanged()方法,标记状态已经改变的事实
		setChanged();
		//调用两种notifyObservers()方法中的一个:
		//notifyObservers() :“拉” ,通知观察者有数据更新,让其自己来获取所需
		//notifyObservers(Object arg) :“推送”,将更新后的所有内容发送给所有观察者
		notifyObservers();   
		//notifyObservers()没有传送数据对象,这表示采用的做法是“拉”。
	}
	
	public void setMeasurements(float temperature, float humidity, float pressure) {
		this.temperature = temperature;
		this.humidity = humidity;
		this.pressure = pressure;
		measurementsChanged();
	}

	/**
	*get方法供观察者在接到通知后来获取自己需要的信息
	*/
	public float getTemperature() {
		return temperature;
	}
	
	public float getHumidity() {
		return humidity;
	}
	
	public float getPressure() {
		return pressure;
	}
}

CurrentConditionsDisplay类(布告板):

import java.util.Observable;
import java.util.Observer;
	
public class CurrentConditionsDisplay implements Observer, DisplayElement {
	Observable observable;
	private float temperature;
	private float humidity;
	
	/**
	*需要一Observable当参数,并将CurrentConditionsDisplay对象登记为观察者
	*/
	public CurrentConditionsDisplay(Observable observable) {
		this.observable = observable;
		observable.addObserver(this);
	}
	/**
	*先确定可观察者属于WeatherData类型,然后利用 getter方法
	*获取温度和湿度测量值,最后调用display()
	*@param Observable 表明发出通知的主题
	*@param arg 传入notifyObservers()的数据对象,没有则为空
	*/
	public void update(Observable obs, Object arg) {
		if (obs instanceof WeatherData) {
			WeatherData weatherData = (WeatherData)obs;
			this.temperature = weatherData.getTemperature();
			this.humidity = weatherData.getHumidity();
			display();
		}
	}
	
	public void display() {
		System.out.println("Current conditions: " + temperature 
			+ "F degrees and " + humidity + "% humidity");
	}
}

使用观察者模式同时保证以上设计原则的思路:
观察者模式保证设计原则的思路


第三章

原则5:开放-关闭

开放关闭原则

模式三:装饰者模式

场景:业务中存在多个相似的对象,它们之间存在很少的属性或方法上的差别,需要一种良好的组合方式以避免“类爆炸”。如基本咖啡类型中加入不同的配料后会产生大量不同的新品,同时也存在大、中、小杯等其他属性的差异,最终体现在价格上。

定义:以组合方式向被装饰的组件中整合抽象类(装饰者),动态地为对象添加、修改属性或方法。在扩展功能上,装饰者提供了比继承更有弹性的替代方案。
注:装饰者通常是配合其他类似于工厂或生成器这样的模式创建的,具有较好的封装。后话。
装饰者模式
典例:java.io包。java.io类图:
在这里插入图片描述
示例:咖啡订单系统
在这里插入图片描述
Beverage超类:

/**
*Beverage相当于抽象的Component类
*/
public abstract class Beverage {
	String description = "Unknown Beverage";
  
	public String getDescription() {
		return description;
	}
	//getDescription()已经在此实现了
	
	//cost()必须在子类中实现
	public abstract double cost();
}

CondimentDecorator装饰者超类:

/**
 * 为了在加上装饰后取代Beverage,CondimentDecorator必须扩展自 Beverage 类。
 */
public abstract class CondimentDecorator extends Beverage {
	public abstract String getDescription();
	//必须重新实现getDescription()方法,新增描述信息
}

Espresso浓缩咖啡基本类:

public class Espresso extends Beverage {
	//通过构造器添加饮料的描述
	public Espresso() {
		description = "Espresso";
	}
	//直接返回Espresso的价格$1.99
	public double cost() {
		return 1.99;
	}
}

HouseBlend咖啡:

public class HouseBlend extends Beverage {
	public HouseBlend() {
		description = "House Blend Coffee";
	}
	public double cost() {
		return .89;
	}
}

咖啡订单测试:

public class StarbuzzCoffee {
 
	public static void main(String args[]) {
		//订一杯纯Espresso,打印出它的描述与价钱
		Beverage beverage = new Espresso();
		System.out.println(beverage.getDescription() 
				+ " $" + beverage.cost());

		//DarkRoast咖啡,加双倍摩卡,加Whip
		Beverage beverage2 = new DarkRoast();
		beverage2 = new Mocha(beverage2);
		beverage2 = new Mocha(beverage2);
		beverage2 = new Whip(beverage2);
		System.out.println(beverage2.getDescription() 
				+ " $" + beverage2.cost());
 
		//HouseBlend咖啡,加Soy、Mocha、Whip
		Beverage beverage3 = new HouseBlend();
		beverage3 = new Soy(beverage3);
		beverage3 = new Mocha(beverage3);
		beverage3 = new Whip(beverage3);
		System.out.println(beverage3.getDescription() 
				+ " $" + beverage3.cost());
	}
}

第四章

广泛使用的编程习惯:简单工厂(非模式)

场景:披萨店推出的披萨口味跟随市场需要动态变化,导致制作工艺常常变动,我们要求一个店员同时负责披萨的制作、准备、烘焙、切块、打包。几天后,店员不满了,披萨制作工艺如此复杂多变,就不能另找一个厨师来专门负责吗?

定义:将同个类不同子类对象的实例化封装在一个工厂类中,专门负责实例化,从而使业务逻辑不关心实例化的具体实现。

模式四:工厂方法模式

场景:现在披萨店开加盟店了,对于同种披萨,在不同地区的制作方式又存在一些地方特色。让一个厨房负责向所有的分店提供披萨似乎不太好,因而我们允许每个分店有自己的厨房(厨房方式对应上面的简单工厂)。当有客人通过总经销商订购分店的披萨时,只需让分店负责即可。其实,在订购流程中的其他步骤,如准备、烘焙、切块、包装、发货…也可以各具地方特色。
定义:定义了一个创建对象的接口(该接口即工厂方法),由子类决定对象具体的创建方式(简单工厂是由一个专门的工厂类)。工厂方法让类把实例化推迟到子类,以达到松耦合。
在这里插入图片描述
示例:披萨加盟店
Creator创建者类:
在这里插入图片描述
产品类:
在这里插入图片描述
平行的类层级:
在这里插入图片描述

原则6:依赖倒置

在这里插入图片描述

模式五:抽象工厂模式

场景: 披萨店通过原料工厂提供原料,各地区需要的原料种类相同,只是每种原料具体的制作略有差别。
定义: 提供一个接口,用于创建相关或依赖对象的家族,而不需要明确的指定具体的类。
在这里插入图片描述
示例:
披萨店抽象工厂方法与不同实例工厂类中的不同方法实现:
在这里插入图片描述


未完待续。。。
个人理解,如有谬误,欢迎指正。

参考文章:
1.Markdown 绘制 UML 图 – PlantUML + Gravizo https://blog.csdn.net/heqiangflytosky/article/details/77050849

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值