设计模式学习笔记,感谢geely老师的《Java设计模式精讲 Debug方式+内存分析》课程。
七大设计原则
-
开闭原则(Open-Closed Principle,OCP):对扩展开放,对修改关闭;用抽象构建框架,用实现构建细节;提高软件系统的可复用性及可维护性。
-
单一职责原则(Simple Responsibility Principle,SRP):不要存在多于一个导致类变更的原因;一个类/接口/方法只负责一项职责;降低类的复杂度,提高类的可读性,提高系统的可维护性,降低变更引起的风险。
-
依赖倒置原则(Dependence Inversion Principle,DIP):高层模块不应该依赖底层模块,二者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象;针对接口编程,不要针对实现编程;减少类与类之间的耦合性,提高系统稳定性,提高代码可读性与可维护性,降低修改程序所造成的风险。
-
接口隔离原则(Interface Segregation Principle,ISP):使用多个专门的接口,而不使用单一的总接口,客户端不应该依赖它不需要的接口;一个类对一个类的依赖应该建立在最小的接口上;建立单一接口,不要建立庞大臃肿的接口;尽量细化接口,接口中的方法尽量少(适度);高内聚低耦合,良好的可读性、可扩展性和可维护性。
-
迪米特法则(Law of Demeter,LoD):又叫最少知道原则(Least Knowledge Principle,LKP),一个对象应当对其他对象有尽可能少的了解;尽量降低类之间的耦合;强调只和朋友交流,不和陌生人说话;朋友:出现在成员变量、方法的输入、输出参数中的类称为成员朋友类,而出现在方法体内部的类不属于朋友类。
-
里氏替换原则(Liskov Substitution Principle,LSP):一个软件实体如果适用一个父类,那一定适用其子类,所有引用父类的地方必须透明地使用其子类对象,子类对象能够替换父类对象,而程序逻辑不变;
子类可以扩展父类的功能,但不能改变父类原有的功能:
- 子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法;
- 子类中可以增加自己特有的方法;
- 子类的方法重载父类的方法时,方法的前置条件(入参)要比父类的方法输入参数更宽松;
- 子类的方法实现父类的方法时(重写/重载/实现抽象方法),方法的后置条件(返回值)要比父类更严格或相等。
约束继承泛滥,开闭原则的一种体现;加强程序的健壮性,变更时可做好更好的兼容性,提高程序的维护性、扩展性,降低需求变更引入的风险。
-
合成/聚合复用原则(Composite/Aggregate Reuse Principle,CARP):尽量使用对象组合(contains-a)/聚合(has-a),而不是继承关系达到软件复用的目的;使系统更灵活,降低类与类之间耦合度,一个类的变化对其他类造成的影响相对较少。
简单工厂
定义:
由一个工厂对象决定创建出哪一种产品类的实例
类型:
创建型,但不属于GOF23种设计模式
适用场景:
工厂类负责创建的对象比较少;客户端只知道传入工厂类的参数,对于如何创建对象(逻辑)不关心
优点:
只需传入一个正确的参数,就可获得所要的对象而无需知道创建细节
缺点:
工厂类的职责相对过重,增加新的产品需要修改工厂类的判断逻辑,违背开闭原则;不易于扩展过于复杂的产品结构
实现:
public abstract class Video {
public abstract void produce();
}
-------------------------------------------------------
public class JavaVideo extends Video{
@Override
public void produce() {
System.out.println("录制Java视频");
}
}
------------------------------------------------------
public class KotlinVideo extends Video{
@Override
public void produce() {
System.out.println("录制Kotlin视频");
}
}
public class VideoFactory {
public Video getVideo(String type) {
if ("java".equals(type)) {
return new JavaVideo();
} else if ("kotlin".equals(type)) {
return new KotlinVideo();
}
return null;
}
/**
public Video getVideo(Class clazz) {
Video video = null;
try {
video = (Video)Class.forName(clazz.getName()).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return video;
}
*/
}
public class Test {
public static void main(String[] args) {
VideoFactory videoFactory = new VideoFactory();
// Video video = videoFactory.getVideo(JavaVideo.class);
Video video = videoFactory.getVideo("java");
if (video != null) {
video.produce();
}
}
}
具体使用场景:
1、Calendar类中的createCalendar()方法体现了简单工厂
public static Calendar getInstance()
{
return createCalendar(TimeZone.getDefault(), Locale.getDefault(Locale.Category.FORMAT));
}
2、
Class.forName("com.mysql.jdbc.Driver");
3、LoggerFactory中使用了简单工厂和工厂模式
public static Logger getLogger(String name) {
ILoggerFactory iLoggerFactory = getILoggerFactory();
return iLoggerFactory.getLogger(name);
}
public static Logger getLogger(Class<?> clazz) {
Logger logger = getLogger(clazz.getName());
if (DETECT_LOGGER_NAME_MISMATCH) {
Class<?> autoComputedCallingClass = Util.getCallingClass();
if (autoComputedCallingClass != null && nonMatchingClasses(clazz, autoComputedCallingClass)) {
Util.report(String.format("Detected logger name mismatch. Given name: \"%s\"; computed name: \"%s\".", logger.getName(),
autoComputedCallingClass.getName()));
Util.report("See " + LOGGER_NAME_MISMATCH_URL + " for an explanation");
}
}
return logger;
}
工厂方法模式(Factory Method Pattern)
解决同一等级结构的产品抽象问题
定义:
定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类,工厂方法让类的实例化推迟到子类中进行
类型:
创建型
适用场景:
创建对象需要大量重复的代码;客户端不依赖于产品类实例如何被创建、实现等细节;一个类通过其子类来指定创建哪个对象
优点:
用户只需要关心所需产品对应的工厂,无须关系创建细节;加入新产品符合开闭原则,提高可扩展性
缺点:
类的个数容易过多,增加复杂度;增加了系统的抽象性和理解难度
实现:
public abstract class VideoFactory {
public abstract Video getVideo();
}
--------------------------------------------------------------
public class JavaVideoFactory extends VideoFactory {
@Override
public Video getVideo() {
return new JavaVideo();
}
}
--------------------------------------------------------------
public class KotlinVideoFactory extends VideoFactory{
@Override
public Video getVideo() {
return new KotlinVideo();
}
}
public class Test {
public static void main(String[] args) {
VideoFactory videoFactory = new JavaVideoFactory();
Video video = videoFactory.getVideo();
video.produce();
VideoFactory videoFactory2 = new KotlinVideoFactory();
Video video2 = videoFactory2.getVideo();
video2.produce();
}
}
简单工厂如果要扩展的话,需要修改VideoFactory中的代码,违背了开闭原则。
而工厂方法模式扩展,不需要变动VideoFactory,只需要创建新的工厂及其实现即可。
具体使用场景:
1、Collection中Iterator
作为抽象产品
Iterator<E> iterator();
ArrayList相当于具体的实现工厂
Itr
作为具体的产品
public Iterator<E> iterator() {
return new Itr();
}
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size;
}
....
}
2、URLStreamHandlerFactory
URLStreamHandler createURLStreamHandler(String protocol);
具体的工厂
private static class Factory implements URLStreamHandlerFactory {
private static String PREFIX = "sun.net.www.protocol";
private Factory() {
}
public URLStreamHandler createURLStreamHandler(String var1) {
String var2 = PREFIX + "." + var1 + ".Handler";
try {
Class var3 = Class.forName(var2);
return (URLStreamHandler)var3.newInstance();
} catch (ReflectiveOperationException var4) {
throw new InternalError("could not load " + var1 + "system protocol handler", var4);
}
}
}
public class Handler extends URLStreamHandler {
protected String proxy;
protected int proxyPort;
protected int getDefaultPort() {
return 80;
}
....
}
3、ILoggerFactory
public interface ILoggerFactory {
public Logger getLogger(String name);
}
抽象工厂模式(Abstract Factory Pattern)
针对产品族
定义:
提供一个创建一系列相关或相互依赖对象的接口,无须指定它们具体的类
类型:
创建型
适用场景:
客户端不依赖于产品类实例如何被创建、实现等细节;强调一系列相关的产品对象(属于同一产品族)一起使用创建对象需要大量重复的代码;提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于具体实现
优点:
具体产品在应用层代码隔离,无须关系创建细节;将一个系列的产品族统一到一起创建
缺点:
规定了所有可能被创建的产品集合,产品族中扩展新的产品困难,需要修改抽象工厂的接口;增加了系统的抽象性和理解难度
产品等级结构与产品族:
实现:
适用于产品等级结构相对固定,需多个产品组合在一起形成产品族
public interface CourseFactory {
Video getVideo();
Note getNote();
}
public class JavaCourseFactory implements CourseFactory{
@Override
public Video getVideo() {
return new JavaVideo();
}
@Override
public Note getNote() {
return new JavaNote();
}
}
public abstract class Video {
public abstract void produce();
}
-------------------------------------------------
public abstract class Note {
public abstract void produce();
}
public class JavaVideo extends Video{
@Override
public void produce() {
System.out.println("Java学习课程");
}
}
-----------------------------------------------
public class JavaNote extends Note {
@Override
public void produce() {
System.out.println("Java学习笔记");
}
}
public class Test {
public static void main(String[] args) {
CourseFactory courseFactory = new JavaCourseFactory();
Video video = courseFactory.getVideo();
Note note = courseFactory.getNote();
video.produce();
note.produce();
}
}
具体使用场景:
1、java.sql.Connection / java.sql.Statement
2、SqlSessionFactory
3、Spring中,AbstractFactoryBean,DefaultListableBeanFactory