最困难的时候,也就是离成功不远的时候。—-拿破仑
单例模式
一个班级只能有一个班主任,所以就要保证一个班主任类只有一个实例,单例模式就是为了解决这种问题,保证一个类仅有一个实例。
核心办法就是把构造函数设置为私有 private
的。这意味着除了 ClassMaster
自己,其他任何类都不能实例化 ClassMaster
对象。
public class ClassMaster {
private String id;
// 班主任名称
private String name;
private String gender;
//唯一实例 必须用static修饰符 ,否则会造成递归的严重的错误
private static ClassMaster instance = new ClassMaster();
//将构造函数设置为私有的
private ClassMaster() {
}
}
我们需要增加一个方法允许其他类访问这个单例的实例,因为类 new
出一个实例的目的就是要给其他类使用的。
public class ClassMaster {
private String id;
// 班主任名称
private String name;
private String gender;
// 唯一实例
private static ClassMaster instance = new ClassMaster();
private ClassMaster() {
}
// 外部类可以通过这个方法访问唯一的实例
public static ClassMaster getInstance() {
return instance;
}
}
spring中的单例思想
有时候从技术角度出发为了节省系统资源,在Spring中类变量使用 @Autowried
注解,能够实现自动注入实例对象。任何 自动 注入实例对象,默认只有一个实例对象,是单例的。
@Autowired
private UsersService usersService;
Spring 会保证只生成一个 UsersServiceImpl
实例注入到多个 Service
或 Control
中。
简单工厂模式
命名
一般来说,工厂类命名为 XXXXFactory
,以 Factory
作为后缀可以提高辨识度,易于理解这个类的作用。
使用简单工厂完成功能开发时,重点就是要明确 什么条件下 创建 什么实例对象 的需求逻辑。
例子
需求:
第二汽车制造厂可以生产“富康牌”轿车以及“爱丽舍”轿车。要求4S店告诉工厂汽车品牌名称即可提取相应的轿车。
分析:
我们需要将具体的汽车类抽象出一个接口 Car
,让具体的汽车类实现接口中的方法,让汽车工厂 CarFactory
生产实例对象就可以了。
类图:
注意类图中有一个抽象类 AbstractCar
,这是为了防止代码重复而创建,因为每个汽车的实现类都要写:
private String brand;
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
所以使用抽象类可以避免每个轿车重复定义 brand
属性。轿车类不再直接实现接口,而是继承 AbstractCar
,这样的话
- 抽象类存放公共属性和方法
- 每个实现类存放自己特有的属性和方法
代码实现:
public class CarShop {
public static void main(String[] args) {
CarFactory carFactory = new CarFactory();
Car fukang = carFactory.makeCar("fukang");
System.out.println(fukang.getBrand());
Car elysee = carFactory.makeCar("elysee");
System.out.println(elysee.getBrand());
}
}
public class CarFactory {
public Car makeCar(String brand) {
Car car = null;
if ("fukang".equals(brand)) {
FuKang fukang = new FuKang();
fukang.setBrand("富康");
car = fukang;
} else if ("elysee".equals(brand)) {
Elysee elysee = new Elysee();
elysee.setBrand("爱丽舍");
car = elysee;
}
return car;
}
}
public interface Car {
public String getBrand();
}
public abstract class AbstractFood implements Food {
private String Name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
public class Elysee extends AbstractFood{
}
public class fukang extends AbstractFood{
}
抽象工厂模式
简单工厂是将多个产品抽象,使用一个工厂统一创建,抽象工厂的主要作用就是把多个工厂进一步抽象。
比如水果工厂只生产水果,而饮料工厂只生产饮料,但是超市既有水果也有饮料,这个时候就需要多个工厂搭配。
类图
进一步抽象出了工厂接口 SnacksFactory
。
工厂接口规定工厂应该提供的商品种类,所以包含所有工厂的方法。
public class FruitFactory implements SnacksFactory {
public Fruit getFruit(Customer customer) {
Fruit fruit = null;
if ("sweet".equals(customer.getFlavor())) {
fruit = new Watermelon();
} else if ("acid".equals(customer.getFlavor())) {
fruit = new Lemon();
} else if ("smelly".equals(customer.getFlavor())) {
fruit = new Durian();
}
return fruit;
}
//水果工厂不提供饮料,水果工厂实现工厂接口后,必须实现getDrink()方法,直接返回null即可
public Drink getDrink(Customer customer) {
return null;
}
}
SnacksFactroyBuilder
称之为 生产工厂的工厂 ,工厂用来生产产品实例,SnacksFactroyBuilder
用来生产工厂实例。public class SnacksFactoryBuilder {
public SnacksFactory buildFactory(String choice) {
if (choice.equalsIgnoreCase("fruit")) {
return new FruitFactory();
} else if (choice.equalsIgnoreCase("drink")) {
return new DrinkFactory();
}
return null;
}
}
扩展
不提倡在工厂中定义
static
方法,因为复杂场景下,实例方法可以被继承,扩展性较好
在使用
Spring
框架的时候,可以为SnacksFactoryBuilder
加上@Component
注解,可以让框架管理实例:@Component
public class SnacksFactoryBuilder {
public SnacksFactory buildFactory(String choice) {
}
}
@Service
public class XxxxxServiceImpl implements XxxxxService {
@Autowired
private SnacksFactoryBuilder snacksFactoryBuilder;
}
观察者模式
例子
1. 被观察类 - Observable
比如天气变化的通知,核心是观察天气,先抽象出天气信息对象。
import java.util.Observable;
public class WeatherData extends Observable {
// 城市
private String cityName;
// 时间
private String time;
// 温度
private String temp;
// 城市固定了就不变了
public WeatherData(String cityName) {
this.cityName = cityName;
}
// 打印天气信息
public String toString() {
return cityName + "," + LocalDate.now().toString() + " " + time + ",气温:" + temp + "摄氏度。";
}
public String getCityName() {
return cityName;
}
public String getTime() {
return time;
}
public String getTemp() {
return temp;
}
}
天气对象类继承了
Observable
类,这个类时Java提供的,继承后就表示是核心的、需要被观察的类。还需要注意的是,这个设计不太一样的地方是没有setter
方法,因为一个WeatherData
代表一个城市的天气,初始化后就不能改变了。2. 数据变化后发起通知
什么时间的气温是多少是要被监听的重要信息,所以要在
WeatherData
中增加一个新的方法来专门处理 ```java import java.util.Observable;
public class WeatherData extends Observable { /**
* 一个城市的气温在某个时刻发生了变化
*/
public void changeTemp(String time, String temp) {
if(time == null || temp == null) {
// 输入数据为空是有问题的,不处理
return;
}
// 与原数据不同,说明发生了变化
if(!time.equals(this.time) || !temp.equals(this.temp)) {
// 标记变化
super.setChanged();
this.time = time;
this.temp = temp;
// 发出通知 this表示把数据对象自己发送出去
super.notifyObservers(this);
}
}
}
<a name="5DxqQ"></a>
#### 3. 谁接收通知 - Observer
`Observer` 是Java提供的观察者类,实现此接口表示作为观察者。并且要自己实现 `update()` 方法,方法签名是接口定义好的,属于固定写法。方法的作用就是接收通知。
```java
import java.util.Observable;
import java.util.Observer;
public class WeatherObserver implements Observer {
private String name;
@Override
public void update(Observable o, Object arg) {
if (arg instanceof WeatherData) {
System.out.print(this.name + " 观察到天气变化为:");
System.out.println(arg.toString());
}
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
4. 调用
观察者可以有多个,观察者对象与被观察者对象谁先 new
出来都可以,但是必须调用 addObserver()
方法把 观察者对象实例 添加到 被观察者实例 中,然后再调用自定义的 changeTemp
方法变更天气,才能触发自动通知。
public class WeatherTest {
public static void main(String[] args) {
// 在天气变化后发邮件的观察者
WeatherObserver w1 = new WeatherObserver();
w1.setName("天气邮件观察者");
// 在天气变化后发短信的观察者
WeatherObserver w2 = new WeatherObserver();
w2.setName("天气短信观察者");
// 城市天气数据
WeatherData weatherData = new WeatherData("余杭");
// 添加观察者
weatherData.addObserver(w1);
weatherData.addObserver(w2);
// 气温变化
weatherData.changeTemp("11:08", "32.8");
// 气温变化
weatherData.changeTemp("14:46", "29.3");
}
}
总结
跟工厂模式不同的是,观察者模式主要描述的是类的行为,而不是如何创建。
跟工厂模式相同的是,观察者模式让 观察者和被观察者双方的耦合度降到最低。