设计模式学习笔记

不定期更新到:https://www.upheart.top/

行为型模式

策略模式

我们来引入一个业务场景:就比如网站里面在618和双十一的时候,会有各种促销,而促销就是课程的一个行为,是一个促销行为,但是这种促销行为有多种实现,网站里面的课程促销

有一个促销策略接口:

public interface PromotionStrategy {
    void doPromotion();
}

有一个立减促销类实现促销策略接口:

public class LiJianPromotionStrategy implements PromotionStrategy{
    @Override
    public void doPromotion() {
        System.out.println("立减促销,课程的价格直接减去配置的价格");
    }
}

满减促销类实现促销策略接口:

public class ManJianPromotionStrategy implements PromotionStrategy{

    @Override
    public void doPromotion() {
        System.out.println("满减促销,满200减20元");
    }
}

还有一个反现促销类实现促销策略接口:

public class FanXianPromotionStrategy implements PromotionStrategy{

    @Override
    public void doPromotion() {
        System.out.println("反现促销,返回的金额存放到网站用户的余额中");
    }
}

还有一个实现促销类,去执行促销策略:

public class PromotionActivity {
    private PromotionStrategy promotionStrategy;

    public PromotionActivity(PromotionStrategy promotionStrategy) {
        this.promotionStrategy = promotionStrategy;
    }

    public void executePromotionStrategy() {
        promotionStrategy.doPromotion();
    }
}

写一个测试类:

public class Test {
    public static void main(String[]args){
        /** 在618的时候,我们使用立减的策略 */
        PromotionActivity promotionActivity618 = new PromotionActivity(new LiJianPromotionStrategy());
        /** 在618的时候,我们使用反现的策略 */
        PromotionActivity promotionActivity1111 = new PromotionActivity(new FanXianPromotionStrategy());

        promotionActivity618.executePromotionStrategy();
        promotionActivity1111.executePromotionStrategy();
    }
}

当我们修改业务的时候,我们就只需要新增一个策略就可以了

我们还可以把策略模式和工厂模式结合到一起再来演进一下:

为了避免空指针异常,我们没有促销活动的时候,我们可以还写一个空的促销策略:

public class EmptyPromotionStrategy implements PromotionStrategy {
    @Override
    public void doPromotion() {
        System.out.println("无促销");
    }
}

这个就是一个促销策略工厂的实现

public class PromotionStrategyFactory {
    private static Map<String, PromotionStrategy> PROMOTION_STRATEGY_MAP = new HashMap<>();
    static {
        PROMOTION_STRATEGY_MAP.put(PromotionKey.LIJIAN, new LiJianPromotionStrategy());
        PROMOTION_STRATEGY_MAP.put(PromotionKey.FANXIAN, new FanXianPromotionStrategy());
        PROMOTION_STRATEGY_MAP.put(PromotionKey.MANJIAN, new ManJianPromotionStrategy());
    }

    private static final PromotionStrategy NON_PROMOTION = new EmptyPromotionStrategy();

    private PromotionStrategyFactory() {

    }

    public static PromotionStrategy getPromotionStrategy(String promotionKey) {
        PromotionStrategy promotionStrategy = PROMOTION_STRATEGY_MAP.get(promotionKey);
        return promotionStrategy == null ? NON_PROMOTION : promotionStrategy;
    }

    private interface PromotionKey{
        String LIJIAN = "LIJIAN";
        String FANXIAN = "FANXIAN";
        String MANJIAN = "MANJIAN";
    }
}

现在,我们再来测试一下:

public class Test {
    public static void main(String[]args){

        /** 我们来创建一个promotionKey */
        String promotionKey = "LIJIAN";

        PromotionActivity promotionActivity = new PromotionActivity(PromotionStrategyFactory.getPromotionStrategy(promotionKey));
        promotionActivity.executePromotionStrategy();
    }
}

策略模式一般都是不会单独的去使用的,一般会结合单例、结合工厂方法模式或者是结合享元模式去使用

迭代器模式

有一个课程类:

public class Course {
    private String name;

    public Course(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

}

还有一个CourseAggregate接口,对课程进行处理:

public interface CourseAggregate {

    void addCourse(Course course);
    void removeCourse(Course course);
	/**获取迭代器 */
    CourseIterator getCourseIterator();
}

这个就是处理接口的实现类:

public class CourseAggregateImpl implements CourseAggregate {

    private List courseList;

    public CourseAggregateImpl() {
        this.courseList = new ArrayList();
    }

    @Override
    public void addCourse(Course course) {
        courseList.add(course);
    }

    @Override
    public void removeCourse(Course course) {
        courseList.remove(course);
    }

    @Override
    public CourseIterator getCourseIterator() {
        return new CourseIteratorImpl(courseList);
    }
}

这个就是迭代器接口:

public interface CourseIterator {
    Course nextCourse();
    boolean isLastCourse();

}

而这个就是迭代器接口的实现类:

public class CourseIteratorImpl implements CourseIterator {

    private List courseList;
    private int position;
    private Course course;
    public CourseIteratorImpl(List courseList){
        this.courseList=courseList;
    }

    @Override
    public Course nextCourse() {
        System.out.println("返回课程,位置是: "+position);
        course=(Course)courseList.get(position);
        position++;
        return course;
    }

    @Override
    public boolean isLastCourse(){
        if(position< courseList.size()){
            return false;
        }
        return true;
    }
}

测试方法:

public class Test {

    public static void main(String[] args) {
        Course course1 = new Course("Java电商一期");
        Course course2 = new Course("Java电商二期");
        Course course3 = new Course("Java设计模式精讲");
        Course course4 = new Course("Python课程");
        Course course5 = new Course("算法课程");
        Course course6 = new Course("前端课程");

        CourseAggregate courseAggregate = new CourseAggregateImpl();

        courseAggregate.addCourse(course1);
        courseAggregate.addCourse(course2);
        courseAggregate.addCourse(course3);
        courseAggregate.addCourse(course4);
        courseAggregate.addCourse(course5);
        courseAggregate.addCourse(course6);

        System.out.println("-----课程列表-----");
        printCourses(courseAggregate);

        courseAggregate.removeCourse(course4);
        courseAggregate.removeCourse(course5);

        System.out.println("-----删除操作之后的课程列表-----");
        printCourses(courseAggregate);
    }

    public static void printCourses(CourseAggregate courseAggregate){
        CourseIterator courseIterator= courseAggregate.getCourseIterator();
        while(!courseIterator.isLastCourse()){
            Course course=courseIterator.nextCourse();
            System.out.println(course.getName());
        }
    }
}

模板方法模式

我们引入一个业务场景:制作视频课程,要制作ppt,还要去写上一个手记,还有提供一些前端的图片素材 ,像前端的课程就会提供图片素材,而后端的课程就不会提供图片素材,不同的课程的制作步骤,主线上是一致的,但是在细分上还是有一些不同,像手记并不是所有的课程都要写,有些课程需要写手记 ,而有些课程就不需要写手记,我们就可以把这个方法制作成一个勾子方法

有一个抽象类:

public abstract class ACourse {
    /** 声明成final就是不希望子类去覆盖这个方法 */
    protected final void makeCourse() {

    }

    final void makePPT() {
        System.out.println("制作PPT");
    }

    final void makeVideo() {
        System.out.println("制作视频");
    }
    
    /** 这个编写手记是一个可选项 */
    final void writeArticle() {
        System.out.println("编写手记");
    }

    /** 我们就要给这个编写手记声明一个勾子方法 */
    /** 这个并不是一个final方法,子类是可以进行覆盖的 */
    protected boolean needWriteArticle() {
        return false;
    }

    abstract void packageCourse();
}

Java设计模式的课程类:

public class DesignPatternCourse extends ACourse {
    @Override
    void packageCourse() {
        System.out.println("提供课程Java源代码");
    }
}

前端课程类:

public class FECourse extends ACourse {
    @Override
    void packageCourse() {
        System.out.println("提供课程的前端代码");
        System.out.println("提供课程的图片等多媒体素材");
    }
}

我们重新编写这个抽象类,编写制作课程的方法:

public abstract class ACourse {
    /** 声明成final就是不希望子类去覆盖这个方法 */
    protected final void makeCourse() {
        this.makePPT();
        this.makeVideo();
        /** 这里是否需要写手记交由勾子方法来决定 */
        if (needWriteArticle()) {
            this.writeArticle();
        }
        this.packageCourse();
    }

    final void makePPT() {
        System.out.println("制作PPT");
    }

    final void makeVideo() {
        System.out.println("制作视频");
    }
    
    /** 这个编写手记是一个可选项 */
    final void writeArticle() {
        System.out.println("编写手记");
    }

    /** 我们就要给这个编写手记声明一个勾子方法 */
    /** 这个并不是一个final方法,子类是可以进行覆盖的 */
    protected boolean needWriteArticle() {
        return false;
    }

    abstract void packageCourse();

}

我们来进行测试一下:

public class Test {
    public static void main(String[]args){
        System.out.println("后端设计模式课程start--");
        ACourse designPatternCourse = new DesignPatternCourse();
        designPatternCourse.makeCourse();
        System.out.println("后端设计模式课程end--");

        System.out.println("前端式课程start--");
        ACourse feCourse = new FECourse();
        feCourse.makeCourse();
        System.out.println("前端课程end--");
    }
}

现在,我们的设计模式课程需要写手记,我们在这个类里面就是可以重写勾子方法:

public class DesignPatternCourse extends ACourse {
    @Override
    void packageCourse() {
        System.out.println("提供课程Java源代码");
    }

    @Override
    protected boolean needWriteArticle() {
        return true;
    }
}

现在,又一个需求:在前端课程里面,有angular课程,vue课程,有时候,我们的angular课程需要写手记,而vue课程不需要写手记,如果我们单单在FECourse里面重写勾子方法,那么所有的前端课程都要写手记 ,这就不符合需求了

我们就是可以这样来做,定义一个是否要写手记的标识属性,通过构造器的方式来进行注入:

public class FECourse extends ACourse {

    private boolean needWriteArticleFlag = false;

    @Override
    void packageCourse() {
        System.out.println("提供课程的前端代码");
        System.out.println("提供课程的图片等多媒体素材");
    }

    @Override
    protected boolean needWriteArticle() {
        return this.needWriteArticleFlag;
    }

    public FECourse(boolean needWriteArticleFlag) {
        this.needWriteArticleFlag = needWriteArticleFlag;
    }
}

如果想要前端课程写手记 ,我们就是可以这样来写:

public class Test {
    public static void main(String[]args){
        System.out.println("前端式课程start--");
        ACourse feCourse = new FECourse(true);
        feCourse.makeCourse();
        System.out.println("前端课程end--");
    }
}

责任链模式

我们引入一个业务场景:我们的线上的课程在发布的时候,要经过两个人个批准,一个手记的检查人,另外一个是视频的检查人,我们在系统里面也会遇到这种情况,一级一级的进行审批;这个就是一个链条

有一个课程类:

public class Course {
    private String name;
    private String article;
    private String video;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getArticle() {
        return article;
    }

    public void setArticle(String article) {
        this.article = article;
    }

    public String getVideo() {
        return video;
    }

    public void setVideo(String video) {
        this.video = video;
    }

    @Override
    public String toString() {
        return "Course{" +
                "name='" + name + '\'' +
                ", article='" + article + '\'' +
                ", video='" + video + '\'' +
                '}';
    }
}

还有一个批准者抽象类:

/**
 * 批准者
 */
public abstract class Approver {
    /** 责任链的核心就是在类里面包含了一个自己同样类型的一个对象 */
    protected Approver approver;

    public void setNextApprover(Approver approver) {
        this.approver = approver;
    }

    public abstract void deploy(Course course) ;
}

一个是手记的批准者:

public class ArticleApprover extends Approver{

    @Override
    public void deploy(Course course) {
        if (StringUtils.isNoneEmpty(course.getArticle())) {
            System.out.println(course.getName() + "含有手记,批准");
            if (approver != null) {
                approver.deploy(course);
            }
        } else {
            System.out.println(course.getName() + "不含有手记,不批准,流程结束");
            return;
        }
    }
}

一个是视频的批准者:

public class VideoApprover extends Approver {
    @Override
    public void deploy(Course course) {
        if (StringUtils.isNoneEmpty(course.getVideo())) {
            System.out.println(course.getName() + "含有视频,批准");
            if (approver != null) {
                approver.deploy(course);
            }
        } else {
            System.out.println(course.getName() + "不含有视频,不批准,流程结束");
            return;
        }
    }
}

这个就是测试的代码:

public class Test {
    public static void main(String[] args) {
        Approver articleApprover = new ArticleApprover();
        Approver videoApprover = new VideoApprover();

        Course course = new Course();
        course.setName("Java设计模式精讲");
        course.setArticle("Java设计模式精讲的手记");
        course.setVideo("Java设计模式精讲的视频");
        /** 先通过手记的审核才交给视频的审核,视频的审核过了才能进行发布上线 */
        articleApprover.setNextApprover(videoApprover);
        articleApprover.deploy(course); 
    }
}

中介者模式

描述的业务场景就是:每一个课程都有一个学习的群,如qq群

有一个用户类:发送消息的时候,就是通过中介者来进行发送

public class User {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public User(String name) {
        this.name = name;
    }

    public void sendMessage(String message) {
        StudyGroup.showMessage(this,message);
    }
}

中介者:

public class StudyGroup {
    public static void showMessage(User user, String message) {
        System.out.println(new Date().toString()+"["+user.getName()+"]:"+message);
    }
}

测试类:

public class Test {
    public static void main(String[] args) {
        User ldc = new User("ldc");
        User ghl = new User("ghl");

        ldc.sendMessage("hey!ghl");
        ghl.sendMessage("hey!ldc");
    }
}

观察者模式

被观察者对象:

public class Course extends Observable {
    private String courseName;

    public Course(String courseName) {
        this.courseName = courseName;
    }

    public String getCourseName() {
        return courseName;
    }

    public void produceQuestion(Course course,Question question) {
        System.out.println(question.getUserName()+"在"+course.getCourseName()+"提交了一个问题 ");
        setChanged();
        notifyObservers(question);
    }
}

一个问题类:

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 Teacher implements Observer {
    private String teacherName;

    public Teacher(String teacherName) {
        this.teacherName = teacherName;
    }

    @Override
    public void update(Observable o, Object arg) {
        Course course = (Course) o;
        Question question = (Question) arg;
        System.out.println(teacherName+"老师的"+course.getCourseName()+"课程接收到一个"+question.getUserName()+"同学提交的问答:"+question.getQuestionContent());
    }
}

一个测试类:

public class Test {
    public static void main(String[]args){
        Course course = new Course("Java设计模式精讲");
        Teacher teacher = new Teacher("Alpha");

        course.addObserver(teacher);
        //业务逻辑代码
        Question question = new Question();
        question.setUserName("ldc");
        question.setQuestionContent("Java的主函数如何编写");

        course.produceQuestion(course, question);
    }
}

命令模式

我们引入一个业务场景:课程里面是有视频的,我们想要局部关闭某一个视频,或者是局部打开某一个视频,如第一章节是开放的,是可以免费看的,而其他章节的课程就是需要购买了之后才能观看的;现在,管理员决定把第二章节也免费观看,然后又过了一阵,把第三章节的视频给进行开放了;又过一阵,把第二章节给关闭了;就是这么一个业务场景

有一个命令类:

public interface Command {
    void execute(); 
}

还有一个视频课程类:

public class CourseVideo {
    private String name;

    public CourseVideo(String name) {
        this.name = name;
    }
    public void open() {
        System.out.println(this.name+"课程开放");
    }
    public void close() {
        System.out.println(this.name+"课程关闭");
    }
}

还有两个课程开启和关闭的类:

public class CloseCourseVideoCommand implements Command {

    private CourseVideo courseVideo;

    public CloseCourseVideoCommand(CourseVideo courseVideo) {
        this.courseVideo = courseVideo;
    }

    @Override
    public void execute() {
        courseVideo.close();
    }
}
public class OpenCourseVideoCommand implements Command {
    private CourseVideo courseVideo;

    public OpenCourseVideoCommand(CourseVideo courseVideo) {
        this.courseVideo = courseVideo;
    }

    @Override
    public void execute() {
       courseVideo.open();
    }
}

还有一个添加命令的类:

public class Staff {
    private List<Command> commandList = new ArrayList<>();

    public void addCommand(Command command) {
        commandList.add(command);
    }

    public void executeCommands() {
        for (Command command : commandList) {
            command.execute();
        }
        commandList.clear();
    }
}

测试类:

public class Test {
    public static void main(String[] args) {
        CourseVideo courseVideo = new CourseVideo("Java设计模式");
        OpenCourseVideoCommand openCourseVideoCommand = new OpenCourseVideoCommand(courseVideo);
        CloseCourseVideoCommand closeCourseVideoCommand = new CloseCourseVideoCommand(courseVideo);

        Staff staff = new Staff();
        staff.addCommand(openCourseVideoCommand);
        staff.addCommand(closeCourseVideoCommand);
        staff.executeCommands();
    }
}

创建型模式

单例模式

单例模式

简单工厂模式

有一个视频的基类(是一个抽象类)

public abstract class Video {
    public abstract void product();
}

有两个类继承它,并对里面的方法进行实现:

public class JavaVideo extends Video {
    @Override
    public void product() {
        System.out.println("录制Java课程视频");
    }
}
public class Python extends Video {
    @Override
    public void product() {
        System.out.println("录制Python的课程视频");
    }
}

现在,我们有一个简单工厂类:

public class VideoFactory {
    public Video getVideo(String type) {
        if ("java".equalsIgnoreCase(type)) {
            return new JavaVideo();
        } else if ("python".equalsIgnoreCase(type)) {
            return new Python();
        }
        return null;
    }
}

测试代码如下:

public class Test {
    public static void main(String[]args){
        VideoFactory videoFactory = new VideoFactory();
        Video video = videoFactory.getVideo("java");
        if (video == null) {
            return;
        }
        video.product();
    }
}

具体的产生类的方法都在工厂类里面,这个就是简单工厂模式

但是,如果我们还要录制一个FE的前端课程,那么,我们就要对工厂类里面的方法进行扩展,那么这个并不符合开闭原则

现在,我们来用反射来演进一下:

public class VideoFactory {
    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);
        if (video == null) {
            return;
        }
        video.product();
    }
}

这里从一定原则上讲是符合开闭原则的

如果我们要new什么类,那我们就只需要传入这个类的类型就可以了,而这个工厂是需要变化的

工厂方法模式

业务场景和之前的简单工厂一样,我们直接对简单工厂里面的代码进行改造

把之前的工厂类改成一个抽象类,里面只留一个待实现的抽象方法:

public abstract class VideoFactory {
    public abstract Video getVideo();
}

创建一个创建JavaVideoFactory的工厂类,继承于VideoFactory这个抽象类:

public class JavaVideoFactory extends VideoFactory {
    @Override
    public Video getVideo() {
        return new JavaVideo();
    }
}

同理,我们再创建一个PythonVideoFactory的工厂类:

public class PythonVideoFactory extends VideoFactory {
    @Override
    public Video getVideo() {
        return new PythonVideo();
    }
}

VideoFactory只定义一个默认的契约,具体创建哪一种对象由具体的子类工厂去实现

测试如下:

public class Test {
    public static void main(String[]args){
        VideoFactory videoFactory = new JavaVideoFactory();
        Video video = videoFactory.getVideo();
        video.product();
    }
}

抽象工厂模式

现在,我们提一个业务场景,现在提出了新的要求:每一个课程不仅仅要有视频,还要有对应的手记

手记类:

public abstract class Article {
    public abstract void produce();
}

课程工厂类:

public interface CourseFactory {
    /** 获取视频 */
    Video getVideo();

    /** 获取手记 */
    Article getArticle();
}

Java手记类:

public class JavaArticle extends Article {
    @Override
    public void produce() {
        System.out.println("编写Java课程手记");
    }
}

产品族里面的工厂类就可以这样来写了:

public class JavaCourseFactory implements CourseFactory {
    @Override
    public Video getVideo() {
        return new JavaVideo();
    }

    @Override
    public Article getArticle() {
        return new JavaArticle();
    }
}

这里就是把视频工厂和手记工厂合在了一起;作为一个产品族

测试:只要是从Java产品族里面拿的肯定是Java的视频和Java的手记

public class Test {
    public static void main(String[]args){
        CourseFactory courseFactory = new JavaCourseFactory();
        Article article = courseFactory.getArticle();
        Video video = courseFactory.getVideo();
        /** 只要是从Java产品族里面拿的肯定是Java的视频和Java的手记 */
        article.produce();
        video.produce();
    }
}

建造者模式

我们来建造一个视频课程:
首先,创建一个课程类:

public class Course {
    private String courseName;
    private String coursePPT;
    private String courseVideo;
    private String courseArticle;
    /** 问题和答案 */
    private String courseQA;

    public String getCourseName() {
        return courseName;
    }

    public void setCourseName(String courseName) {
        this.courseName = courseName;
    }

    public String getCoursePPT() {
        return coursePPT;
    }

    public void setCoursePPT(String coursePPT) {
        this.coursePPT = coursePPT;
    }

    public String getCourseVideo() {
        return courseVideo;
    }

    public void setCourseVideo(String courseVideo) {
        this.courseVideo = courseVideo;
    }

    public String getCourseArticle() {
        return courseArticle;
    }

    public void setCourseArticle(String courseArticle) {
        this.courseArticle = courseArticle;
    }

    public String getCourseQA() {
        return courseQA;
    }

    public void setCourseQA(String courseQA) {
        this.courseQA = courseQA;
    }

    @Override
    public String toString() {
        return "Course{" +
                "courseName='" + courseName + '\'' +
                ", coursePPT='" + coursePPT + '\'' +
                ", courseVideo='" + courseVideo + '\'' +
                ", courseArticle='" + courseArticle + '\'' +
                ", courseQA='" + courseQA + '\'' +
                '}';
    }
}

我们再来创建一个抽象类:

public abstract class CourseBuilder {

    public abstract void buildCourseName(String courseName);
    public abstract void buildCoursePPT(String coursePPT);
    public abstract void buildCourseVideo(String courseVideo);
    public abstract void buildCourseArticle(String courseArticle);
    public abstract void buildCourseQA(String courseQA);

    public abstract Course makeCourse();
}

我们再来创建一个实现CourseBuilder 的子类:

public class CourseActualBuilder extends CourseBuilder {

    /** 这里把课程组合到实际的Builde当中 */
    private Course course = new Course();

    @Override
    public void buildCourseName(String courseName) {
        course.setCourseName(courseName);
    }

    @Override
    public void buildCoursePPT(String coursePPT) {
        course.setCoursePPT(coursePPT);
    }

    @Override
    public void buildCourseVideo(String courseVideo) {
        course.setCourseVideo(courseVideo);
    }

    @Override
    public void buildCourseArticle(String courseArticle) {
        course.setCourseArticle(courseArticle);
    }

    @Override
    public void buildCourseQA(String courseQA) {
        course.setCourseQA(courseQA);
    }

    @Override
    public Course makeCourse() {
        return course;
    }
}

这里还引入了一个教练类:

public class Coach {
    private CourseBuilder courseBuilder;
    /** 这里的CourseBuilder通过set的方式给注入进来 */
    public void setCourseBuilder(CourseBuilder courseBuilder) {
        this.courseBuilder = courseBuilder;
    }

    public Course makeCourse(String courseName,String coursePPT,
                             String courseVideo,String courseArticle,String courseQA) {
        this.courseBuilder.buildCourseName(courseName);
        this.courseBuilder.buildCoursePPT(coursePPT);
        this.courseBuilder.buildCourseVideo(courseVideo);
        this.courseBuilder.buildCourseArticle(courseArticle);
        this.courseBuilder.buildCourseQA(courseQA);

        return this.courseBuilder.makeCourse();
    }
}

测试:

public class Test {
    public static void main(String[]args){
        /** 利用多态,抽象类的引用指向子类的实现 */
        CourseBuilder courseBuilder = new CourseActualBuilder();
        Coach coach = new Coach();
        /** 这里利用set方法注入进去 */
        coach.setCourseBuilder(courseBuilder);
        Course course = coach.makeCourse("Java设计模式", "Java设计模式PPT", "Java设计模式视频", "Java设计模式手记", "Java设计模式问答");
        System.out.println(course);
    }
}

使用静态内部类

把具体的实体类和实体类对应的Builder写在一个类里面

这里一个很关键的地方就是this和静态内部类的使用:

public class Course {
    
    private String courseName;
    private String coursePPT;
    private String courseVideo;
    private String courseArticle;
    /** 问题和答案 */
    private String courseQA;

    public Course(CourseBuilder courseBuilder) {
        this.courseName = courseBuilder.courseName;
        this.coursePPT = courseBuilder.coursePPT;
        this.courseVideo = courseBuilder.courseVideo;
        this.courseArticle = courseBuilder.courseArticle;
        this.courseQA = courseBuilder.courseQA;
    }

    public static class CourseBuilder{
        private String courseName;
        private String coursePPT;
        private String courseVideo;
        private String courseArticle;
        /** 问题和答案 */
        private String courseQA;

        public CourseBuilder builderCourseName(String courseName) {
            this.courseName = courseName;
            return this;
        }
        public CourseBuilder builderCoursePPT(String coursePPT) {
            this.coursePPT = coursePPT;
            return this;
        }
        public CourseBuilder builderCourseVideo(String courseVideo) {
            this.courseVideo = courseVideo;
            return this;
        }
        public CourseBuilder builderCourseArticle(String courseArticle) {
            this.courseArticle = courseArticle;
            return this;
        }
        public CourseBuilder builderCourseQA(String courseQA) {
            this.courseQA = courseQA;
            return this;
        }

        public Course build() {
            return new Course(this);
        }
    }

    @Override
    public String toString() {
        return "Course{" +
                "courseName='" + courseName + '\'' +
                ", coursePPT='" + coursePPT + '\'' +
                ", courseVideo='" + courseVideo + '\'' +
                ", courseArticle='" + courseArticle + '\'' +
                ", courseQA='" + courseQA + '\'' +
                '}';
    }
}

我们再来写上一个测试类来测试:

public class Test {
    public static void main(String[]args){
        Course course = new Course.CourseBuilder()
                .builderCourseName("Java设计模式")
                .builderCoursePPT("Java设计模式PPT")
                .builderCourseVideo("Java设计模式视频")
                .builderCourseArticle("Java设计模式手记")
                .builderCourseQA("Java设计模式问答").build();
        System.out.println(course);
    }
}

结构型模式

组合模式

有一个课程的抽象类:

public abstract class CatalogComponent {
    public void add(CatalogComponent catalogComponent) {
        throw new UnsupportedOperationException("不支持添加操作");
    }
    public void remove(CatalogComponent catalogComponent) {
        throw new UnsupportedOperationException("不支持删除操作");
    }
    public String getName(CatalogComponent catalogComponent) {
        throw new UnsupportedOperationException("不支持获取名称操作");
    }
    public double getPrice(CatalogComponent catalogComponent) {
        throw new UnsupportedOperationException("不支持获取价格操作");
    }
    public void print() {
        throw new UnsupportedOperationException("不支持打印操作");
    }
}

课程类:

public class Course extends CatalogComponent{
    private String name;
    private double price;

    public Course(String name, double price) {
        this.name = name;
        this.price = price;
    }

    @Override
    public String getName(CatalogComponent catalogComponent) {
        return this.name;
    }

    @Override
    public double getPrice(CatalogComponent catalogComponent) {
        return this.price;
    }

    @Override
    public void print() {
        System.out.println("Course Name :"+name+" price"+price);
    }
}

目录类:

public class CourseCatalog extends CatalogComponent {
    private List<CatalogComponent> items = new ArrayList<>();

    private String name;

    public CourseCatalog(String name) {
        this.name = name;
    }

    @Override
    public void add(CatalogComponent catalogComponent) {
        items.add(catalogComponent);
    }

    @Override
    public void remove(CatalogComponent catalogComponent) {
        items.remove(catalogComponent);
    }

    @Override
    public void print() {
        for (CatalogComponent catalogComponent : items) {
            catalogComponent.print();
        }
    }
}

测试类:

public class Test {
    public static void main(String[]args){
        CatalogComponent linuxCourse = new Course("Linux课程", 11);
        CatalogComponent windowsCourse = new Course("windows课程", 11);

        CatalogComponent javaCourseCatalog = new CourseCatalog("Java课程目录");
        CatalogComponent mmallCatalog1 = new Course("Java电商一期",55);
        CatalogComponent mmallCatalog2 = new Course("Java电商二期",66);
        CatalogComponent designPattern = new Course("Java设计模式",77);

        javaCourseCatalog.add(mmallCatalog1);
        javaCourseCatalog.add(mmallCatalog2);
        javaCourseCatalog.add(designPattern);

        CatalogComponent ldcMainCourseCatalog = new CourseCatalog("网站课程主目录");
        ldcMainCourseCatalog.add(linuxCourse);
        ldcMainCourseCatalog.add(windowsCourse);
        ldcMainCourseCatalog.add(javaCourseCatalog);

        ldcMainCourseCatalog.print();
    }
}

适配器模式

类适配器模式

有一个被适配器类:

public class Adaptee {
    public void adapteeRequest() {
        System.out.println("被适配者的方法");
    }
}

这个是目标方法的接口:

public interface Target {
    void request();
}

这个是目标方法的实现:

/** 具体的实现类 */
public class ConcreteTarget implements Target {
    @Override
    public void request() {
        System.out.println("ConcreteTarget目标方法");
    }
}

而这个就是适配类:继承于被适配类,实现目标方法的接口:

public class Adapter extends Adaptee implements Target {
    @Override
    public void request() {
        super.adapteeRequest();
    }
}

我们来进行测试一下:

public class Test {
    public static void main(String[]args){
        Target target = new ConcreteTarget();
        target.request();

        /** 现在,我们就来通过适配器类来进行实现 */
        Target adapterTarget = new Adapter();
        adapterTarget.request();
    }
}

这个时候,我们调用适配类里面的方法,然后转到被适配类里面的方法

对象适配器模式

同上面一样:有一个目标接口

还有一个具体的目标类

以及被适配的类

适配类和上面的有一些不同,这里被适配类不是继承过来的,而是作为属性组合到里面来,然后通过对象来调用被适配类里面的方法:

public class Adapter implements Target {

    private Adaptee adaptee = new Adaptee();

    @Override
    public void request() {
        adaptee.adapteeRequest();
    }
}

现在,我们来测试一下:我们在拷贝的时候,一定要注意包是否引对

public class Test {
    public static void main(String[]args){
        Target target = new ConcreteTarget();
        target.request();

        /** 现在,我们就来通过适配器类来进行实现 */
        Target adapterTarget = new Adapter();
        adapterTarget.request();
    }
}

桥接模式

桥接模式重要的就是把抽象和实现分离出来,然后中间通过组合来搭建他们之间的桥梁

业务场景:中国有很多银行,有中国农业银行和中国工商银行;关于我们的账号,有定期账号和活期账号,
一个就是银行一个就是我们的账号

有一个账户接口:

public interface Account {
    /** 打开我们的账号,打开账号,就要返回账号 */
    Account openAccount();
    
    /** 打开我们的账号,查看为什么账户类型,是定期类型还是活期类型 */
    void showAccountType();

}

而这个就是一个定期账号:

/** 定期的账号 */
public class DepositAccount implements Account {
    @Override
    public Account openAccount() {
        System.out.println("定期账号");
        return new DepositAccount();
    }

    @Override
    public void showAccountType() {
        System.out.println("这是一个定期账号");
    }
}

这个是一个活期的账号:

/** 活期账号 */
public class SavingAccount implements Account {
    @Override
    public Account openAccount() {
        System.out.println("打开活期账号");
        return new SavingAccount();
    }

    @Override
    public void showAccountType() {
        System.out.println("这是一个活期账号");
    }
}

现在,我们就去写一个银行类:将Account账户接口组合到这个银行类:

public abstract class Bank {
    /** 只有子类能拿到这个Account的这个接口 */
    protected Account account;

    /** 组合的时候,可以通过构造器的方式来进行注入也可以通过set方法的方式来进行注入 */
    public Bank(Account account) {
        this.account = account;
    }

    /** 这里声明成和接口里面的方法名一致,只是方便理解,Bank里面的方法要委托给Account接口里面的方法 */
    abstract Account openAccount();
}

我们现在看到就是Account就是具体的实现,我们要通过这个接口的具体实现,而Bank就是抽象,它是一个抽象类,然后这个抽象类里面的某个行为委托给Account的这个接口

在前面有说到桥接模式指的就是抽象和实现分离;而这里的实现正式这里的Account的实现类

现在这个银行有两个子类去继承它:

一、中国农业银行类:

public class ABCBank extends Bank {
    /**
     * 组合的时候,可以通过构造器的方式来进行注入也可以通过set方法的方式来进行注入
     *
     * @param account
     */
    public ABCBank(Account account) {
        super(account);
    }

    @Override
    Account openAccount() {
        System.out.println("打开中国农业银行账号");
        return account;
    }
}

二、中国工商银行账号

public class ICBCBank extends Bank {
    /**
     * 组合的时候,可以通过构造器的方式来进行注入也可以通过set方法的方式来进行注入
     *
     * @param account
     */
    public ICBCBank(Account account) {
        super(account);
    }

    @Override
    Account openAccount() {
        System.out.println("打开中国工商银行账号");
        return account;
    }
}

Bank的这个抽象类通过组合的方式,把Account的这个接口组合了进来

测试类如下:

public class Test {
    public static void main(String[]args){
        Bank icbcBank = new ICBCBank(new DepositAccount());
        Account icbcAccount = icbcBank.openAccount();
        icbcAccount.showAccountType();

        Bank icbcBank2 = new ICBCBank(new SavingAccount());
        Account icbcAccount2 = icbcBank2.openAccount();
        icbcAccount2.showAccountType();

        Bank abcBank = new ABCBank(new SavingAccount());
        Account abcAccount = abcBank.openAccount();
        abcAccount.showAccountType();
    }
}

装饰者模式

有一个煎饼类:

public class Battercake {
    protected String getDesc() {
        return "煎饼";
    }
    protected int cost() {
        return 8;
    }
}

煎饼加鸡蛋类:

public class BattercakeWithEgg extends Battercake {
    @Override
    public String getDesc() {
        return super.getDesc()+"加一个鸡蛋";
    }

    @Override
    public int cost() {
        return super.cost()+1;
    }

}

煎饼加鸡蛋加香肠类:

public class BattercakeWithEggSausage extends BattercakeWithEgg{
    @Override
    public String getDesc() {
        return super.getDesc()+"一个香肠";
    }

    @Override
    public int cost() {
        return super.cost()+2;
    }
}

测试:

public class Test {
    public static void main(String[]args){
        Battercake battercake = new Battercake();
        System.out.println(battercake.getDesc()+"销售价格:"+battercake.cost());

        BattercakeWithEgg battercakeWithEgg = new BattercakeWithEgg();
        System.out.println(battercakeWithEgg.getDesc()+"销售价格:"+battercakeWithEgg.cost());

        BattercakeWithEggSausage battercakeWithEggSausage = new BattercakeWithEggSausage();
        System.out.println(battercakeWithEggSausage.getDesc()+"销售价格:"+battercakeWithEggSausage.cost());

    }
}

这个时候,有一个人加了两个鸡蛋,这个时候,根据上面的就是不能算出价格的

现在,我们用装饰者模式来写

有一个抽象的煎饼类:

public abstract class ABattercake {
    protected abstract String getDesc();
    protected abstract int cost();
}

煎饼类继承于上面的抽象兼饼类:

public class Battercate extends ABattercake {
    @Override
    protected String getDesc() {
        return "煎饼";
    }

    @Override
    protected int cost() {
        return 8;
    }
}

我们让抽象的装饰者类继承抽象的实体:

public class AbstractDecorator extends ABattercake{
    private ABattercake aBattercake;

    public AbstractDecorator(ABattercake aBattercake) {
        this.aBattercake = aBattercake;
    }

    @Override
    protected String getDesc() {
        return aBattercake.getDesc();
    }

    @Override
    protected int cost() {
        return aBattercake.cost();
    }
}

煎饼添加鸡蛋的装饰类继承于抽象的装饰类:

public class EggDecorator extends AbstractDecorator{

    public EggDecorator(ABattercake aBattercake) {
        super(aBattercake);
    }

    @Override
    protected String getDesc() {
        return super.getDesc()+"加一个鸡蛋";
    }

    @Override
    protected int cost() {
        return super.cost()+1;
    }
}

煎饼添加香肠的装饰类,继承于抽象的装饰类:

public class SausageDecorator extends AbstractDecorator{

    public SausageDecorator(ABattercake aBattercake) {
        super(aBattercake);
    }

    @Override
    protected String getDesc() {
        return super.getDesc()+"加一根香肠";
    }

    @Override
    protected int cost() {
        return super.cost()+2;
    }
}

测试:

public class Test {
    public static void main(String[]args){
        ABattercake aBattercake;
        aBattercake = new Battercate();
        aBattercake = new EggDecorator(aBattercake);
        aBattercake = new EggDecorator(aBattercake);
        aBattercake = new SausageDecorator(aBattercake);
        System.out.println(aBattercake.getDesc()+"价格为:"+aBattercake.cost());
    }
}

你可能感兴趣的:(设计模式)