将可能发生变化的类设计为抽象类,后续变化时,新增类来实现新的业务
可复用性和可维护性强,降低维护代码带来的新风险。
便于理解,提高了代码可读性
如ArrayLsit和LinkedList,不同实现,不同功能。
也就是多态,父类出现的地方都可以用子类替换
参数为List,传入ArrayList,LinkedList,Vector都可以
里式替换需要将父类设计为抽象类或接口,子类实现父类中所有方法
对其他对象要最少了解。
不和陌生人说话,方法中创建的对象属于陌生人
使用多个专门的接口,不要将多余功能加在一个接口上
优先使用组合/聚合(has-a),其次考虑继承(只有is-a关系才使用继承)
组合:员工类包含部门,部门包含员工集合
继承:电脑 与 笔记本电脑,平板电脑,台式电脑等属于继承关系
设计模式就是在长期的开发中,为了解决一些重复出现的问题,经过长期的总结优化,最终确定的一套解决方案。
优点:
- 提高了代码的复用性、可维护性、可靠性、可读性、灵活性
- 提高了程序员的思维能力、编码能力,设计能力,能够设计出标准化的程序
设计模式根据工作类型可划分为:创建型模式、结构性模式、行为型模式
设计一个类时,让他只能创建一个对象(节省资源,保证数据一致性)
单例模式需要实现的功能
单例实现:
单例类一加载,就创建了对象,在调用getInstance
方法之前就存在对象
public class HungrySingleton {
private static HungrySingleton singleton = new HungrySingleton();
private HungrySingleton(){}
public static HungrySingleton getInstance(){
return singleton;
}
}
懒汉式单例:类加载时,并不会去创建对象,只有第一次访问时,才去创建,存在线程安全问题
解决懒汉式单例线程安全:
public class LazySingleton {
private static LazySingleton singleton = null;
private LazySingleton() {}
//方法加锁
//效率低:创建对象只是第一次,后面都是获取对象。每次获取对象只能有一个线程获取,
public static synchronized LazySingleton getInstance(){
if(singleton == null){
singleton = new LazySingleton();
}
return singleton;
}
//代码块加锁 : 效率也低
public static LazySingleton getInstance() {
synchronized (LazySingleton.class) {
if (singleton == null) {
singleton = new LazySingleton();
}
}
return singleton;
}
}
volatile
使用volatile修饰单例对象,主要是为了实现有序性
因为创建对象,给引用赋值的过程,可能被拆分为3个指令
①new Singleton():在内存中申请空间。(这条不会被重排)
②调用构造器初始化对象
③将对象地址赋给引用变量(有可能被重排到第二步执行,造成引用变量执行的是一个半成品对象)
双重检索
总结:
package com.example.java_hign.framework.singleton;
public class LazySingleton {
//volatile 为了保证有序性
private static volatile LazySingleton singleton = null;
private LazySingleton() {}
//双重检索 + volatile
public LazySingleton getInstance(){
//多个线程第一次进入该方法,singleton 为 null
if(singleton == null){
//还没有初始化singleton时,只允许一个线程来创建
synchronized (LazySingleton.class){
//其他线程进来,如果singleton已经被初始化,就直接返回
if(singleton == null){
singleton = new LazySingleton();
}
}
}
//后面线程获取对象时,直接返回创建好的singleton
return singleton;
}
}
工厂:批量创建对象 (属于设计模式中的创建型模式)
定义一个创建产品的工厂接口,具体的产品创建由接口的实现类来完成
并不对外显示创建对象的逻辑,只提供一个接口指向新创建的对象
思想:创建对象和使用对象相分离
什么时候使用工厂模式?
想要在不同的条件下创建不同的对象时
简单工厂模式中创建实例的方法是static修饰,简单工厂模式也叫静态工厂模式
何时使用简单工程模式?
优点
调用者想创建一个对象,只需要知道其名称即可
测试
public class Test {
public static void main(String[] args) {
SimpleFactory productFactory = new SimpleFactory();
Product phone = productFactory.getProduct("com.example.java_hign.factory.Phone");
Product pad = productFactory.getProduct("com.example.java_hign.factory.Pad");
Product computer = productFactory.getProduct("com.example.java_hign.factory.Computer");
phone.displayInfo();
pad.displayInfo();
computer.displayInfo();
}
}
抽象工厂模式是用来创建工厂的(像超级管理员一样,可以创建不同的管理员,再由管理员去做其他事)
抽象工厂中
5.1 使用抽象工厂生成电子产品工厂
使用电子产品工厂生成所属产品对象
public class Test {
public static void main(String[] args) {
//获取电子产品的简单工厂
AbstractFactory factory = FactoryProducer.getFactory(
"com.example.java_hign.factory.abstractfactory.ElectronicSimpleFactory");
//获取电子产品工厂中的产品
ElectronicProduct computer = factory.getElectronicProduct(
"com.example.java_hign.factory.abstractfactory.Computer");
ElectronicProduct pad = factory.getElectronicProduct(
"com.example.java_hign.factory.abstractfactory.Pad");
ElectronicProduct phone = factory.getElectronicProduct(
"com.example.java_hign.factory.abstractfactory.Phone");
//测试产品
computer.displayInfo();
pad.displayInfo();
phone.displayInfo();
}
}
5.2 使用抽象工厂生成阅读产品工厂
使用阅读产品工厂生成所属产品对象
public class Test {
public static void main(String[] args) {
//获取阅读产品的简单工厂
AbstractFactory factory = FactoryProducer.getFactory(
"com.example.java_hign.factory.abstractfactory.ReadSimpleFactory");
//获取阅读产品工厂中的产品
ReadProduct book = factory.getReadProduct(
"com.example.java_hign.factory.abstractfactory.Book");
ReadProduct ebook = factory.getReadProduct(
"com.example.java_hign.factory.abstractfactory.EBook");
book.display();
ebook.display();
}
}
当我们想完成某件事,但有不想直接访问目标时,可以通过代理来帮忙完成
(租房子,自己一个一个找房东(目标)效率太低,通过中间商来帮忙完成)
代理的优点:
实际中用的并不多
静态代理类必须实现和目标类一样的接口
扩展性很差
代理类不需要实现与目标类相同的接口,可以代理任意目标类
但要求目标类都实现接口
动态代理可以对目标类统一进行处理(添加日志)
纯反射机制实现,动态获取目标类的方法
动态生成代理对象,目标类必须实现接口
步骤:
public class Test {
public static void main(String[] args) {
UserDao vipUser = new VipUserDaoImpl();
InvocationHandler proxy = new DynamicProxy(vipUser);
//真正的创建动态代理对象
UserDao userDao = (UserDao) Proxy.newProxyInstance(DynamicProxy.class.getClassLoader(),VipUserDaoImpl.class.getInterfaces() , proxy);
//调用的是invoke方法
userDao.save(new User(20,"张飞"));
}
}
目标类不需要实现接口,采用底层的动态字节码技术,为目标类动态生成子类,在子类中拦截父类方法的调用(采用方法拦截技术实现)。
使用了继承,不能代理final修饰的类
Cglib代理实现:
spring-core-xxx.jar
就可以静态代理是在代码中实现,代理类必须实现和目标类相同的接口,目标类接口修改或增加,代理类也要跟着改。
动态代理在运行时生成,代理类实现InvocationHandler接口,可以代理任意的目标类,要求目标类必须实现接口。
动态代理较于静态代理 : 减少了对接口的依赖,降低了耦合度。