单例模式
现实生活中常出现唯一的现象,比如地球只有一个
为了保证一个类只有一个实例,核心办法就是把构造方法设置为私有的,也就是只有自己才能实例化自己
public class ClassMaster {
private String id;
// 班主任名称
private String name;
private String gender;
// 唯一实例
private static ClassMaster instance = new ClassMaster();
private ClassMaster() {
}
}
这种保证只有一个实例对象的方式就是单例设计模式
为了给其他得类使用还需要增加一个方法,允许其他类访问这个单利的实例
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;
}
}
UML图
spring中的单例
任何自动注入实例对象,默认只有一个实例对象
饿汉模式和懒汉模式
- 饿汉式单例:在定义开始便实例自己
public class Singe{
private static Single single = new Single();
private Single(){}
public static Single instance(){
return single;
}
}
- 懒汉单例:在第一次调用时实例化自己
public class Singe{
private static Single single = null;
private Single(){}
public static Single instance(){
if(single==null){
single = new Single()
}
return single;
}
}
区别:
-
线程安全:
饿汉式天生线程安全,可以直接用于多线程而不会出现问题。
懒汉式本身非线程安全,需要人为实现线程安全 -
资源加载和性能:
饿汉式在类创建的同时就实例化一个静态对象出来,不管之后会不会使用这个单例,都会占据一定的内存,造成内存泄漏,但相应的,在第一次调用时速度也会更快。
而懒汉式顾名思义,会延迟加载,在第一次使用该单例的时候才会实例化对象出来,第一次调用时要做初始化,如果要做的工作比较多,性能上会有些延迟,之后就和饿汉式一样了。
简单工厂模式
程序中的工厂是生产实例对象的地方
为了实现不同条件创建不同对象的需求,核心问题是:
- 减少代码重复,减少相同逻辑代码
- 降低耦合紧密,减少代码之间的相互影响
实现简单工厂:
- 从具体的产品类抽象出接口,java面向接口编程,所以工厂应该生产一种产品而不是一个产品
- 把生产实例对象的过程收敛到工厂类中实现
UML图
public class FruitFactory {
public static 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;
}
}
工厂主要的优点在于职责明确,餐馆和甜品店只需要告诉工厂口味,就可以获得工厂的水果,但又不需要知道具体是什么水果
一般工厂命名为XXXFactory
,这样的辨识度较高易于理解
重点在于明确什么条件下创建什么实例对象
抽象工厂模式
对于一批,多种类型的对象需要创建时,使用抽象工厂模式
简单工厂主要是把多个产品抽象,使用一个工厂统一创建,抽象工厂则是把多个工厂进一步抽象
UML图
就是进一步抽象工厂接口(SnackFactory)多出一个SnacksFactoryBuilder
工厂接口
规定工厂应该提供什么样的产品,包含了所有工厂的方法
public interface SnacksFactory {
// 取得水果
public Fruit getFruit(Customer customer);
// 取得饮料
public Drink getDrink(Customer customer);
}
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;
}
//水果工厂不提供饮料
public Drink getDrink(Customer customer) {
return null;
}
}
工厂的工厂
工厂用来生成产品实例,生产工厂的工厂用于生成工厂实例
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;
}
}
SnacksFactoryBuilder
的buildFactory()
方法并不是static
的,在复杂场景下尽量不要使用static方法
工厂模式结合Spring工程
在工厂中减少定义static
方法是为了在使用Spring框架时,可以为FactoryBuilder
加上@Component
注解让框架管理实例
@Component
public class FactoryBuilder {
public Factory buildFactory(String choice) {
}
}
同样任何需要使用工厂的地方只需要使用@Autowired
注解让框架自动注入实例即可,这样可以让工厂模式的代码与Spring互为一体,扩展性更好,易于维护
观察者模式
订阅和通知这种场景比较适合观察者模式
把需要观察的对象类也就是会改变的类继承Observable
类,继承了就表示是核心的,需要观察的类
和以往的模型设计不一样,需要观察的类要去掉全部属性的setter
方法
Observable提供的setChanged()
方法就是标记被观察者对象发送了变化,notifyObservers()
就是发出通知.
接受通知的类就叫做观察者,观察者需要实现Observer
接口,表示为观察者
@Override
public void update(Observable o, Object arg) {
}
- 第一个参数就是被观察者对象
- 第二个参数就是额外的信息,具体就是调用
super.notifyObservers()
是传入的参数对象,传入什么对象,arg的值就是什么对象
update()方法的作用就是接受通知,系统在super.notifyObservers()发出通知后,及调用了所有的观察者的update()方法
观察者可以有多个,无论观察者还是被观察者对象谁先new出来都可以,但必须先调用addObserver()
方法把观察者对象实例添加到被观察者实例中,然后再调用自定义的changeTemp()
方法改变天气,才能触发通知