架构设计原则
开闭原则:是指一个软件实体(如类、模块和函数)应该对扩展开放,对修改关闭。
依赖倒置原则:是指设计代码结构时,高层模块不应该依赖低层模块,二者都应该依赖其抽象。抽象不应该依赖细节,细节应该依赖抽象。
单一职责:是指一个类只负责一个主要任务,避免因一个类负责两个以上任务时,修改其中一个任务代码导致另一个任务代码受到连带影响。
接口隔离原则:是指用多个专门的接口,而不使用单一的总接口,客户端不应该依赖它不需要的接口
迪米特原则:是指一个对象应该对其他对象保持最少的了解,又叫最少知道原则,尽量降低类与类之间的耦合度。
里氏替换原则:子类可以扩展父类的功能,但不能改变父类原有的功能。
合成复用原则:是指尽量使用对象组合,而不是继承关系达到软件复用的目的。
工厂模式是创建型模式,这种模式的特点是可以将对象的创建和使用相分离,适用于对象的创建比较复杂,希望对外隐藏对象的创建过程的场景。同时由于对象的创建和使用相分离,使得逻辑代码与对象的创建解耦,方便管理对象。
具体的实现方法上有三种模式,分别是:简单工厂模式(Simple Factory Pattern)、工厂方法模式(Factory Method Pattern)、抽象工厂模式(Abstract Factory Pattern)。
简单工厂模式适用于:对象的创建逻辑简单,对象的继承关系相对简单,需要被工厂方法创建的对象数量较少的情况。
例如:在学校我们要学习多种课程,我们就可以定义一个课程类接口,不同的课程教授不同的内容,于是我们有了JavaCourse子类、和PythonCourse子类。
定义Course接口:
public interface Course {
void recode();
}
定义Course接口子类JavaCourse
public class JavaCourse implements Course{
@Override
public void recode() {
System.out.println("Java课程正在录制");
}
}
定义Course接口子类PythonCourse
public class PythonCourse implements Course{
@Override
public void recode() {
System.out.println("Python课程正在录制");
}
}
定义CourseType枚举类,方便告诉工厂我们需要的对象类型。
public enum CourseType {
JAVA_COURSE,PYTHON_COURSE;
}
定义工厂
public class CourseFactory {
public static Course createCourse(CourseType courseType){
switch(courseType){
case JAVA_COURSE: return new JavaCourse();
case PYTHON_COURSE: return new PythonCourse();
default: return null;
}
}
}
测试方法
public class Client {
public static void main(String[] args) {
Course javaCourse = CourseFactory.createCourse(CourseType.JAVA_COURSE);
Course pythonCourse = CourseFactory.createCourse(CourseType.PYTHON_COURSE);
javaCourse.recode();
pythonCourse.recode();
}
}
测试结果如下
可以将对象的创建与逻辑代码解耦,方便后期的代码维护。
所有的产品类都在一个工厂中产生,工厂类的职责相对过重,不易于扩展过于复杂的产品结构。
工厂方法模式主要解决的是产品扩展问题,当随着产品类数量的增多,每个产品类的实例化逻辑也各不相同时,如果再将所有的产品类实例化过程都集中在一个工厂方法中,就会使得该方法变得巨大无比,不利用程序的维护和可读性。
工厂方法模式的解决思路是:工厂父类定义统一的接口,为每一种产品类单独定义一个创造工厂,由调用者决定具体调用哪个工厂方法。
工厂方法模式适用于:对象的创建逻辑复杂,或经常需要增添新的类。
定义课程类接口
public interface Course {
void recode();
}
定义JavaCourse子类
public class JavaCourse implements Course{
@Override
public void recode() {
System.out.println("Java课程正在录制");
}
}
定义PythonCourse子类
public class PythonCourse implements Course{
@Override
public void recode() {
System.out.println("Python课程正在录制");
}
}
定义工厂接口
public interface CourseFactory {
Course createCourse();
}
定义JavaCourseFactory
public class JavaCourseFactory implements CourseFactory{
@Override
public Course createCourse() {
return new JavaCourse();
}
}
定义PythonCourseFactory
public class PythonCourseFactory implements CourseFactory{
@Override
public Course createCourse() {
return new PythonCourse();
}
}
测试类
public class Client {
public static void main(String[] args) {
CourseFactory javaCourseFactory = new JavaCourseFactory();
CourseFactory pythonCourseFactory = new PythonCourseFactory();
Course javaCourse = javaCourseFactory.createCourse();
Course pythonCourse = pythonCourseFactory.createCourse();
javaCourse.recode();
pythonCourse.recode();
}
}
测试结果
关系类图:
工厂方法模式需要创建对应的课程工厂实例,才能获取到对应课程对象。可能会有小伙伴觉得这不是脱了裤子放屁——多此一举吗?明明可以直接new 一个我们需要的课程对象。其实是因为这个例子比较简单,通常工厂方法模式用于对象的创建逻辑比较复杂,代码繁琐的场景。
如JDBC常用的PreparedStatement对象,还记得创建PreparedStatemenet对象的步骤吗?
加载驱动–>连接数据库–>获取Connection对象–>获取PreparedStatement对象。
运用工厂方法模式就可以将这些步骤封装起来,简化程序代码。
方便产品扩展,工厂类的职责清晰,结构简单。例如我如果想在项目中添加一个linux课程,只需要在项目中添加一个LinuxCourse类,和LinuxCourseFactory类即可,不用对之前的代码做任何修改。
每种产品类都对应着一种工厂类,当商品的种类增多时,维护起来有一定难度。
工厂方法模式中只有一个抽象方法,要想获得不同类型的产品对象,就要创建不同的工厂子类对象,而抽象工厂则是让一个工厂负责创建多个不同类型的对象。
抽象工厂模式适用于:需要一组对象共同完成某种功能时,并且可能存在多组对象完成不同功能的情况。(同属于同一个产品族的产品);系统结构稳定,不会频繁的增加对象。
接着上面的例子,现在学校不仅要求老师们上课,还要提供课程录像和课堂笔记,这样就有java视频类,python视频类,java笔记类,python笔记类,四个类;如果还采取工厂方法模式就需要四个工厂方法类;随着课程数量的增多,工厂方法的数量也会增多,最终会变得臃肿,难以维护。
而使用抽象工厂模式,只需要两个工厂方法即可。
定义Note接口
public interface Note {
void show();
}
定义JavaNote实现类
public class JavaNote implements Note{
@Override
public void show() {
System.out.println("这是Java的笔记");
}
}
定义PythonNote实现类
public class PythonNote implements Note{
@Override
public void show() {
System.out.println("这是Python的笔记");
}
}
定义Video接口
public interface Video {
void play();
}
定义JavaVideo实现类
public class JavaVideo implements Video{
@Override
public void play() {
System.out.println("正在播放Java的视频");
}
}
定义PythonVideo实现类
public class PythonVideo implements Video{
@Override
public void play() {
System.out.println("正在播放Python的视频");
}
}
定义Factory接口
public interface Factory {
Note createNote();
Video createVideo();
}
定义JavaFactory
public class JavaFactory implements Factory{
@Override
public Note createNote() {
return new JavaNote();
}
@Override
public Video createVideo() {
return new JavaVideo();
}
}
定义PythonFactory实现类
public class PythonFactory implements Factory {
@Override
public Note createNote() {
return new PythonNote();
}
@Override
public Video createVideo() {
return new PythonVideo();
}
}
测试类
public class Client {
public static void main(String[] args) {
Factory javaFactory = new JavaFactory();
Factory pythonFactory = new PythonFactory();
Note javaNote = javaFactory.createNote();
Video javaVideo = javaFactory.createVideo();
Note pythonNote = pythonFactory.createNote();
Video pythonVideo = pythonFactory.createVideo();
javaNote.show();
javaVideo.play();
pythonNote.show();
pythonVideo.play();
}
}
运行结果
关系类图
纵向扩展困难:如果要在一个产品系列中增加一个新的产品,就需要对工厂接口,及工厂子类的代码进行修改。例如:现在不仅要求老师提供录屏和笔记,还要提供家庭作业homework;这就需要在工厂接口Factory,以及他的所有子类中添加createHomework( )方法,违背了开闭原则。