最困难的时候,也就是离成功不远的时候。—-拿破仑
单例模式
一个班级只能有一个班主任,所以就要保证一个班主任类只有一个实例,单例模式就是为了解决这种问题,保证一个类仅有一个实例。
核心办法就是把构造函数设置为私有 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 注解,能够实现自动注入实例对象。任何 自动 注入实例对象,默认只有一个实例对象,是单例的。
@Autowiredprivate 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注解,可以让框架管理实例:@Componentpublic class SnacksFactoryBuilder {public SnacksFactory buildFactory(String choice) {}}
@Servicepublic class XxxxxServiceImpl implements XxxxxService {@Autowiredprivate 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");
}
}
总结
跟工厂模式不同的是,观察者模式主要描述的是类的行为,而不是如何创建。
跟工厂模式相同的是,观察者模式让 观察者和被观察者双方的耦合度降到最低。

