若有雷同全部来自java设计模式精讲,经过个人理解修改完成
简单工厂模式
不属于GOF23种设计模式但是抽象工厂模式和工厂方法模式都是由他演变而来的
定义:
由一个工厂对象决定创建出哪一种产品类的实例
使用场景:
创建的对象比较少,客户端只知道传入对象的参数,对于如何创建对象不关心
优点:
只需要传入正确的参数就可以获取你所需要的对象,无需知道创建细节
缺点:
工厂类的职责相对过重,增加新的产品的时候要修改工厂类的判断逻辑
总结:
在应用层中不要直接依赖创建类,而是通过创建中间工厂来选择相对应的创建类
UML图解析:
利用反射实现判断传入的中间的课程类型,通过实现课程工厂类来实现解开Test(应用函数对工厂类的的创建),但是在增加新的课程的时候不需要修改其他的类
工厂方法模式
定义:
定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类,工厂方法让类的实例化推迟到子类中进行
适用场景:
创建对象需要大量的重复代码,应用层不依赖与产品如何被创建,实现的细节,一个类通过其子类来指定创建哪个对象
优点:
用户只需要关心所需要产品对应的工厂,无需关心创建细节,加入新的产品符合开闭原则,无需关心创建细节
缺点:
类的个数容易过多,增加复杂性
总结:
UML图展示:
抽象工厂模式
定义:
抽象工厂模式提供一个创建一系列相关或者互相依赖对象的接口,无需指定具体的类
使用场景:
客户端不依赖于产品类实例如何被创建,实现等细节,强调一系列相关的产品对象一起使用创建对象需要大量重复的代码,提供一个产品类的库,所有的产品以相同的接口出现,从而使得客户端不依赖于具体实现类
优点:
将一个系列的产品族统一到一起进行创建
缺点:
规定了所有可能被创建的产品集合,产品组中扩展新的产品困难,需要修改抽象工厂的接口,增加系统的抽象性和理解难度
总结:
要理解商品组和商品等级的问题,其实就是从两个角度去看待意见商品的属性,通过品牌等区分为java和py通过不同的东西确定是视频还是笔记
UML图示:
装饰者模式
定义:
在不改变原有对象的基础上,将功能附加到对象上,提供了比继承更有弹性的替代方法(拓展原有对象功能)
优点:
继承的有力补充,比继承灵活,不改变原有的对象的情况下给一个对象拓展功能,通过使用不同的装饰类以及这些装饰类的排列组合,可以实现不同的效果
缺点:
会出现更多的代码,更多的类,增加程序的复杂性,在动态装饰的时候会更加复杂
使用场景:
拓展一个类的功能或者给一个类添加附加职责,动态的给一个对象添加功能,这些功能可以在动态的撤销
UML:
观察者模式
定义:
定义了对象一对多依赖,让多个观察者对象同时监听某一个主题对象,当主题对象发生变化时,他的所有依赖者就是观察者都会收到通知并且跟新
使用场景:
关联行为场景,建立一套触发机制
优点:
观察者和被观察者之间建立一个抽象的耦合,观察者模式支持广播通信
缺点:
观察这之间有躲过的细节依赖,提高时间消耗及陈旭复杂度,使用要得当避免循环调用
总结:
java提供了一个OBSERVABLE和OBSER
代码实例介绍:
course类来表示被观察的对象,他继承了Observable类,这个类提供了两个私有属性一个叫changed,表示被观察者也就是这里的course类在发生变化的时候这个值会变更成true,第二各私有属性是obs,是一个Vector一个动态数组,用于储存观察者也就是下面的teacher类,可以看到他直接在初始化构造器的时候直接初始化了,另外这个类还提供了addObserver用于添加观察者对象,deleteObserver删除观察者等对象
public class Course extends Observable {
private String courseName;
public String getCourseName() {
return courseName;
}
public void setCourseName(String courseName) {
this.courseName = courseName;
}
public Course(String courseName) {
this.courseName = courseName;
}
public void produceQuestion(Course course, Question question){
System.out.println(question.getUserName()+" in "+course.getCourseName() +
" commit a question: "+question.getQuestionContent());
//表示向观察者提交更改信息
setChanged();
//把具体的信息传递到观察者
notifyObservers(question);
}
}
teacher用于表示观察者,也是是消息传递到达的对象,update复写他爹Observer 的方法,表示在接收到改变的状态的时候会收到两个默认的参数,第一个参数Observable o表示在被观察的对象是哪个这里就是course,第二个参数arg就是被观察者传来的数据信息,就是下面的question,重写的update方法就是表示观察者在接收到被观察对象之后默认执行的语句
public class Teacher implements Observer {
private String teacherName;
public Teacher(String teacherName) {
this.teacherName = teacherName;
}
public String getTeacherName() {
return teacherName;
}
@Override
public void update(Observable o, Object arg) {
//o是被观察者的对象
Course course = (Course)o;
//arg是需要传递的消息对象
Question question = (Question)arg;
System.out.println(teacherName+"老师的"+
course.getCourseName()+"收到了来自"+
question.getUserName()+"的问题"+
question.getQuestionContent());
}
}
question用于表示课程变动的时候向teacher发送的消息格式
public class Question {
private String userName;
private String questionContent;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getQuestionContent() {
return questionContent;
}
public void setQuestionContent(String questionContent) {
this.questionContent = questionContent;
}
}
最后测试类
public class Test {
public static void main(String[] args) {
Course course = new Course("java设计模式精讲");
Teacher teacher = new Teacher("worry");
Teacher teacher1 = new Teacher("al");
//添加观察者
course.addObserver(teacher);
course.addObserver(teacher1);
//业务逻辑
Question question = new Question();
question.setUserName("gee");
question.setQuestionContent("main如何编写");
//表示告诉所有观察者我变化了,传递的两个参数一个是当前课程一个是传递消息的格式
course.produceQuestion(course,question);
}
}
UML图:
建造者模式
定义:
将一个复杂对象的构成与他的表示分离,使得同样的构建过程也可以创建不同的表示,用户只需要指定需要创建的类型就可以得到他们,创建的过程不需要知道
使用场景:
如果一个对象有非常复杂的内部结构(很多属性),想把复杂对象的创建和使用分离
优点:
封装性好,创建和使用分离,拓展性好,建造类之间独立,一定程度上解耦
缺点:
产生多余的builder对象,产品的内部类发生变化,建造者都要修改成本太大
总结:
UML图:
第一种不依赖于内部类的实现方法
第二种实现内部类
单例模式
定义:
保证一个类仅有一个实例,并提供一个全局访问点
使用场景:
想确保任何情况下都绝对只有一个实例
优点:
在内存里面只有一个实例,减少内存的开销,可以避免对资源的多冲占用,设置全局访问点,严格控制访问点
缺点:
没有接口,拓展困难
重点:
私有构造器,线程安全,延迟加载,序列化和反序列化安全,反射
总结:
单例的难点不在于私有化构造器,而是在保证如何确保他的唯一性
多种写法:
懒汉式写法:
/**
* @author Worry
* 懒汉式写法
*/
public class Singleton {
/**
*在内部私有化一个实例
*/
private static Singleton instance;
/**
* 私有化构造器
*/
private Singleton (){
}
/**
* 对外开放一个获取单例对象的方法,所有的访问都要通过这个方法进行
* 懒汉的意思就是只有在使用的时候才会去创建
* 在synchronized情况下保证相对的线程安全
*/
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
饿汉式写法:
/**
* @author Worry
* 饿汉式写法,太勤快了在类创建的时候就已经初始化好了,
*/
public class Singleton {
//在加载类的时候直接初始化对象并私有化
private static Singleton instance = new Singleton();
//私有化构造器
private Singleton (){}
//对外提供一个获取的方法
public static Singleton getInstance() {
return instance;
}
}
内部类写法:
/**
* @author Worry
* 静态内部类写法,
*/
public class Singleton {
private Singleton (){
}
//对外暴露一个获取实例的方法
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
// 将类的实例化用finally来实例在内部类中
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
}
双重校验锁:
/**
* @author Worry
* 双重校验锁写法
*/
public class Singleton {
// volatile关键字能保证每次读取这个对象的时候是从内存中读取的最新值
private volatile static Singleton singleton;
// 私有化构造器
private Singleton (){}
// 对外暴露一个可以获取对象的方法
public static Singleton getSingleton() {
if (singleton == null) {
// synchronized关键字在保证在同一时间只有一个线程能对他进行操作
// 相当于加了双重验证一样
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
代理模式
定义:
为其他对象提供一种代理,用来控制对这个对象的访问,代理对象在客户端和目标对象之间起到中介的作用
使用场景:
保护目标对象,增强目标对象
优点:
将代理对象和真实被调用的目标对象分离,一定程度降低了系统的耦合性,拓展性好
缺点:
会造成设计中类的数目增加,在中间增加一个代理对象,会造成请求的数度变慢,因为执行的过程变长了,增加了系统的复杂度
拓展:
总结:
代理模式就类似于房东和中介的关系,房东将某些权限全权赐予中介,中介就能代理房东来进行各种操作,这样调用者可以在不知道房东是谁的情况下都可以完成对租房子这一行为的操作
UML图:
课程里面的实现带入了分库的实现方式,多了我就只把代理模式的部分打出来,这里其他的部分其实都不用看只是mvc的伪代码,一个实体类order,一各service接口以及一个接口实现类,一个dao接口 以及一个到实现类,OrderServiceStaticProxy类做了什么事情第一把一个service实现初始化到自己类中然后通过写和service一样的参数方法来实现对saveorder的增强
public class OrderServiceStaticProxy {
private IOrderService iOrderService;
public int saveOrder(Order order){
beforeMethod();
iOrderService = new OrderServiceImpl();
int userId = order.getUserId();
int dbRouter = userId % 2;
System.out.println("静态代理分配到【db"+dbRouter+"】处理数据");
int reault = iOrderService.saveOrder(order);
afterMethod();
return reault;
}
private void beforeMethod(){
System.out.println("静态代理 before code");
}
private void afterMethod(){
System.out.println("静态代理 after code");
}
}
适配器模式
定义:
将一个类的接口转换成客户期待的另一个接口,使原本不兼容的类可以一起工作
使用场景:
已经存在的类,他的方法和需求不匹配的时(方法结果相同或者类似),不是产品设计阶段考虑的设计模式u,是随着软件维护,由于不同产品,不同厂家造成功能类似二接口不同的情况下的解决方案
优点:
能提高类的透明度和复用,现有的类复用但不需要改变,目标类和适配器类解耦,提高程序拓展性
缺点:
适配器编写过程中需要全面考虑,可能会增加系统的复杂性,增加代码刻度的难度
总结:
和外观模式比较没有那么庞大,因为都是争对类和接口的,在这其中需要搞明白三个角色,一个是被适配的方法,一个是目标方法(就是被适配者要被适配到的形态),中间有一个适配方法,专门把被适配的方法转化成适配的目标方法,这里讲有点云里雾里,举个例子,充电器的插头是usb的,手机的充电口是typec的,数据线是负责把usb接口转成typec的接口给手机充电的,这里的usb就是上述的要被适配的方法,这里的typec就是目标方法,这里的数据线就是中间那个转化的方法
UML图:
通过继承的方法
通过组合的方法,一个被适配类ac220,一个目标适配类接口dc5,一个适配类poweradapter