设计模式就该这样学-读书笔记

七大软件设计原则

1.开闭原则

对扩展开放,对修改关闭
eg:
一个课程接口

一个java课程实现课程接口

如果课程的价格需要优惠,则不要在原来的java类中修改getPrice方法,而是新建一个折扣类,实现java课程类
重写getPrice()方法.这样就是扩展了原来类的功能,但是么有修改原来类的功能

2.依赖倒置原则

高层代码不应该依赖低层代码,两者应该依赖于抽象
抽象不应该依赖细节,细节应该依赖抽象

public class Tom {
    public void setiCourse(ICourse iCourse) {
        this.iCourse = iCourse;
    }

    public void study(){
        iCourse.study();
    }
}

public interface ICourse {
    void study();
}

public class JavaCourse implements ICourse {
    public void study() {
        System.out.println("Tom正在学习Java课程");
    }
}

public class PythonCourse implements ICourse {
    public void study() {
        System.out.println("Tom正在学习Python课程");
    }
}

3.单一职责

一个类负责一个功能,如果有多个职责,一旦需求变更,改了其中一个功能的代码可能导致另外一个功能受到影响
一个Class、Interface、Method只负责一项职责

4.接口隔离原则

5.迪米特法则

指一个对象应该对其他对象保持最少的了解,尽量降低类与类之间的耦合。
迪米特法则主要强调只和朋友交流,不和陌生人说话。


public class Employee {

    public void checkNumberOfCourses(){
        List<Course> courseList = new ArrayList<Course>();
        for (int i = 0; i < 20; i ++){
            courseList.add(new Course());
        }
        System.out.println("目前已发布的课程数量为:" + courseList.size());
    }
}
public class TeamLeader {

    public void commandCheckNumber(Employee employee){
        employee.checkNumberOfCourses();
    }
}
teamLeader不应该跟Course有关联,应该将teamLeader和Course隔离开
TeamLeader只跟Employee打交道
Course应该只跟Employee有关联

6.里氏替换原则

子类对象能够替换父类对象,而程序逻辑不变。
(1)子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法。
(2)子类中可以增加自己特有的方法。
(3)当子类的方法重载父类的方法时,方法的前置条件(即方法的输入参数)要比父类的方法更宽松。
(4)当子类的方法实现父类的方法时(重写/重载或实现抽象方法),方法的后置条件(即方法的输出/返回值)要比父类的方法更严格或相等。

7.合成复用原则

尽量使用对象组合(has-a)或对象聚合(contanis-a)的方式实现代码复用,而不是用继承关系达到代码复用的目的

新建Mysql的数据连接
public class DBConnection {
    public String getConnection(){
        return "Mysql连接";
    };
}

public class ProductDao {
    private DBConnection dbConnection;
    public void setConnection(DBConnection dbConnection){
        this.dbConnection = dbConnection;
    }
    public void addProduct(){
        String conn = dbConnection.getConnection();
        System.out.println("获得数据库连接");
    }
}
```db
在这种情况下,如果业务需要支持Oracle的连接,可以在DBConnection上增加Oracle的连接
但是这样就违背了开闭原则
正确做法应该是:将DBConnection改为抽象类

public abstract class DBConnection {
    public abstract String getConnection();
}

public class MyOracleConnection extends DBConnection {
    public String getConnection() {
        return "获取Oracle数据连接";
    }
}

public class MySQLConnection extends DBConnection {
    public String getConnection() {
        return "获取MySQL数据连接";
    }
}

public class ProductDao {
    private DBConnection dbConnection;
    public void setConnection(DBConnection dbConnection){
        this.dbConnection = dbConnection;
    }
    public void addProduct(){
        String conn = dbConnection.getConnection();
        System.out.println("获得数据库连接");
    }
}

public class CopTest {
    public static void main(String[] args) {
        ProductDao productDao = new ProductDao();
        productDao.setConnection(new MySQLConnection());
        productDao.addProduct();
    }
}

工厂模式

简单工厂模式

public class Client {

    public static void main(String[] args) {

        new SimpleFactory().makeProduct(1);
    }

    //抽象产品
    public interface IProduct {
        void doSomething();
    }
    //具体产品:ProductA
    static class ConcreteProductA implements IProduct{
        public void doSomething() {
            System.out.println("I am Product A");
        }
    }
    //具体产品:ProductB
    static class ConcreteProductB implements IProduct{
        public void doSomething() {
            System.out.println("I am Product B");
        }
    }
    //具体产品:ProductC
    static class ConcreteProductC implements IProduct{
        public void doSomething() {
            System.out.println("I am Product C");
        }
    }

    final class Const {
        static final int PRODUCT_A = 0;
        static final int PRODUCT_B = 1;
        static final int PRODUCT_C = 2;
    }

    //SimpleFactory.java
    static class SimpleFactory {
        public static IProduct makeProduct(int kind) {
            switch (kind) {
                case Const.PRODUCT_A:
                    return new ConcreteProductA();
                case Const.PRODUCT_B:
                    return new ConcreteProductB();
                case Const.PRODUCT_C:
                    return new ConcreteProductC();
            }
            return null;
        }
    }
}

eg:

public interface ICouse {
    void record();
}

public class JavaCouse implements ICouse {
    public void record(){
        System.out.println("录制Java课程");
    }
}

public class PythonCouse implements ICouse {
    public void record(){
        System.out.println("录制Python课程");
    }
}

public class CourseFactory {
    public ICouse create(Class<? extends ICouse> clazz){
        try {
            if (null != clazz) {
                return clazz.newInstance();
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }
}

public class Test {
    public static void main(String[] args) {
        ICouse couse = new CourseFactory().create(JavaCouse.class);
        couse.record();
    }
}
  • jdk源码中的应用
  • 简单工厂优点: 简单
  • 简单工厂缺点: 每次增加产品都要修改工厂类,不太符合开闭原则

工厂模式

工厂模式当新增产品时也新增一个工厂的实现类,达到不改变原来的代码的目的

  • 工厂方法模式在Logback源码中的应用
  • 工厂模式优点: 每增加一个产品增加一个工厂类,符合满足迪米特法则、依赖倒置原则和里氏替换原则
    工厂模式缺点: 类太多, 每个工厂只生产一个产品,可以用抽象工厂模式解决

抽象工厂模式

相较于普通工厂模式,抽象工厂模式的规模更大,是围绕一个超级工厂创建其他的工厂,可以理解为生产工厂的工厂

/**
 * 我们使用手机工厂和色彩工厂来演示,虽然他们没有什么关联,但是他们都是工厂
 * 手机工厂生产三种不同的手机
 * 色彩工厂生产三种不同的色彩
 */

//产品种类接口,手机的接口,我们可以直接通过手机来访问不同品牌的手机
interface Phone{
    String type();
}

class HuaWei implements Phone{

    @Override
    public String type() {
        return "HuaWei MateX";
    }
}

class IPhone implements Phone{

    @Override
    public String type() {
        return "IPhone 12MAX";
    }
}

class OnePlus implements Phone{
    @Override
    public String type() {
        return "OnePlus 9";
    }
}

//色彩接口
interface Color{
    String color();
}

class White implements Color{
    @Override
    public String color() {
        return "white";
    }
}

class Green implements Color{

    @Override
    public String color() {
        return "green";
    }
}

class Blue implements Color{

    @Override
    public String color() {
        return "blue";
    }
}

//创建手机工厂和颜色工厂的抽象工厂
public abstract class AbstractFactory {
    public abstract Phone getPhone(String phone);
    public abstract Color getColor(String color);
}

//继承抽象工厂,创建工厂类
//手机工厂
class PhoneFactory extends AbstractFactory{

    @Override
    public Phone getPhone(String phone) {
        if ("HuaWei".equals(phone)){
            return new HuaWei();
        }else if ("IPhone".equals(phone)){
            return new IPhone();
        }else if ("OnePlus".equals(phone)){
            return new OnePlus();
        }else {
            return null;
        }
    }

    @Override
    public Color getColor(String color) {
        return null;
    }
}
//颜色工厂
class ColorFactory extends AbstractFactory {

    @Override
    public Phone getPhone(String phone) {
        return null;
    }

    @Override
    public Color getColor(String color) {
        if(color == null){
            return null;
        }
        if("white".equals(color)){
            return new White();
        } else if("green".equals(color)){
            return new Green();
        } else if("blue".equals(color)){
            return new Blue();
        }
        return null;
    }
}

//创建工厂创造器
class FactoryProducer{
    public static AbstractFactory getFactory(String factory){
        if ("phone".equals(factory)){
            return new PhoneFactory();
        }else if("color".equals(factory)){
            return new ColorFactory();
        }else {
            return null;
        }
    }
}

//测试类
class AbstractFactoryDemo{
    public static void main(String[] args) {
        //获取一个手机工厂
        AbstractFactory phoneFactory=FactoryProducer.getFactory("phone");
        //获取一个手机
        Phone phone=phoneFactory.getPhone("IPhone");
        //查看手机类型
        System.out.println(phone.type());

        //获取一个色彩工厂
        AbstractFactory colorFactory=FactoryProducer.getFactory("color");
        //获取一个色彩
        Color color=colorFactory.getColor("blue");
        //查看色彩
        System.out.println(color.color());
    }
}
  • 在Spring中,所有工厂都是BeanFactory的子类。通过对BeanFactory的实现,我们可以从Spring的容器访问Bean。
    根据不同的策略调用getBean()方法,从而获得具体对象。
    BeanFactory的子类主要有ClassPathXmlApplicationContext、XmlWebApplicationContext、
    StaticWebApplicationContext、StaticPortletApplicationContext、GenericApplicationContext
    和Static ApplicationContext。
    在Spring中,DefaultListableBeanFactory实现了所有工厂的公共逻辑。

单例模式

饿汉式:在类加载的时候立即初始化,绝对线程安全

public class HungrySingleton {

    private static final HungrySingleton instance = new HungrySingleton();

    private HungrySingleton(){}

    public static HungrySingleton getInstance(){
        return  instance;
    }
}

public class HungryStaticSingleton {
    private static final HungryStaticSingleton instance;

    static {
        instance = new HungryStaticSingleton();
    }

    private HungryStaticSingleton(){}

    public static HungryStaticSingleton getInstance(){
        return  instance;
    }
}

缺点是:有用没有的类都进行初始化,有点浪费内存

懒汉式:

1.给获取实例的类加上synchronize即可,缺点是性能低,如果线程数量太多,会导致阻塞严重

public class LazySimpleSingletion {
    //静态块,公共内存区域
    private static LazySimpleSingletion instance;

    private LazySimpleSingletion(){}

    public synchronized static LazySimpleSingletion getInstance(){
        if(instance == null){
            instance = new LazySimpleSingletion();
        }
        return instance;
    }
}

2.双重检测锁方式:类似于高铁进站要验两次票

public class LazyDoubleCheckSingleton {
    private volatile static LazyDoubleCheckSingleton instance;
    private LazyDoubleCheckSingleton(){}

    public static LazyDoubleCheckSingleton getInstance(){
        //检查是否要阻塞
        if (instance == null) {
            synchronized (LazyDoubleCheckSingleton.class) {
                //检查是否要重新创建实例
                if (instance == null) {
                    instance = new LazyDoubleCheckSingleton();
                    //指令重排序的问题
                }
            }
        }
        return instance;
    }
}

双重检测锁的方式可以实现线程安全,但还是用到了synchronize,
3. 内部类写法

//这种形式兼顾饿汉式单例模式的内存浪费问题和synchronized的性能问题
//完美地屏蔽了这两个缺点
//自认为史上最牛的单例模式的实现方式
//利用内部类不使用不创建的方法
public class LazyStaticInnerClassSingleton {
    //使用LazyInnerClassGeneral的时候,默认会先初始化内部类
    //如果没使用,则内部类是不加载的
    private LazyStaticInnerClassSingleton(){
        if(LazyHolder.INSTANCE != null){
            throw new RuntimeException("不允许创建多个实例,避免通过反射生成多个实例");
        }
    }
    //每一个关键字都不是多余的,static是为了使单例的空间共享,保证这个方法不会被重写、重载
    private static LazyStaticInnerClassSingleton getInstance(){
        //在返回结果以前,一定会先加载内部类
        return LazyHolder.INSTANCE;
    }

    //利用了Java本身语法特点,内部类默认不加载
    private static class LazyHolder{
        private static final LazyStaticInnerClassSingleton INSTANCE = new LazyStaticInnerClassSingleton();
    }

}

4.枚举类写法

public class User {
    //私有化构造函数
    private User(){ }
 
    //定义一个静态枚举类
    static enum SingletonEnum{
        //创建一个枚举对象,该对象天生为单例
        INSTANCE;
        private User user;
        //私有化枚举的构造函数
        private SingletonEnum(){
            user=new User();
        }
        public User getInstnce(){
            return user;
        }
    }
 
    //对外暴露一个获取User对象的静态方法
    public static User getInstance(){
        return SingletonEnum.INSTANCE.getInstnce();
    }
}

public class Test {
    public static void main(String [] args){
        System.out.println(User.getInstance());
        System.out.println(User.getInstance());
        System.out.println(User.getInstance()==User.getInstance());
    }
}

原型模式

对象复制创建新的对象
如果需要深拷贝,则可以通过序列化和反序列化的方式实现

建造者模式

将一个复杂对象的构建过程与它的表示分离,使得同样的构建过程可以创建不同的表示,属于创建型设计模式

public class CourseBuilder {

    private Course course = new Course();

    public CourseBuilder addName(String name){
        course.setName(name);
        return this;
    }

    public CourseBuilder addPpt(String ppt){
        course.setPpt(ppt);
        return this;
    }

    public CourseBuilder addVideo(String video){
        course.setVideo(video);
        return this;
    }

    public CourseBuilder addNote(String note){
        course.setNote(note);
        return this;
    }

    public CourseBuilder addHomework(String homework){
        course.setHomework(homework);
        return this;
    }

    public Course builder(){
        return course;
    }

}

public static void main(String[] args) {
        CourseBuilder builder = new CourseBuilder()
                .addName("设计模式")
                .addPpt("【PPT课件】")
                .addVideo("【录播视频】");

        System.out.println(builder.builder());
    }
  • 通常sql拼接成查询语句都会用到构建者模式,mybatis和spring中也会用到
  • StringBuffer中的append方法就用到了构建者模式

代理模式

生活中的租房中介、婚姻介绍、经纪人、快递、事务代理、日志监听等,都是代理模式的实际体现。

public class Client {

    public static void main(String[] args) {

        Proxy proxy = new Proxy(new RealSubject());
        proxy.request();

    }

    //抽象主题角色
    interface ISubject {
        void request();
    }

    //代理主题角色
    static class Proxy implements ISubject {

        private ISubject subject;

        public Proxy(ISubject subject){
            this.subject = subject;
        }


        public void request() {
            before();
            subject.request();
            after();
        }

        public void before(){
            System.out.println("called before request().");
        }

        public void after(){
            System.out.println("called after request().");
        }
    }

    //真实主题角色
    static class RealSubject implements ISubject {

        public void request() {
            System.out.println("real service is called.");
        }

    }

}
  • 1.静态代理:
    例子:老上三给儿子张三找媳妇
public interface IPerson {

    void findLove();

}

public class ZhangSan implements IPerson {
    public void findLove() {
        System.out.println("儿子要求:肤白貌美大长腿");
    }
}

public class ZhangLaosan implements IPerson {

    private ZhangSan zhangsan;

    public ZhangLaosan(ZhangSan zhangsan) {
        this.zhangsan = zhangsan;
    }

    public void findLove() {
        System.out.println("张老三开始物色");
        zhangsan.findLove();
        System.out.println("开始交往");
    }

}

public class Test {
    public static void main(String[] args) {
        ZhangLaosan zhangLaosan = new ZhangLaosan(new ZhangSan());
        zhangLaosan.findLove();
    }
}

2.动态代理:
eg:婚姻介绍所

public interface IPerson {
    void findLove();
}

public class JdkMeipo implements InvocationHandler {
    private IPerson target;
    public IPerson getInstance(IPerson target){
        this.target = target;
        Class<?> clazz =  target.getClass();
        return (IPerson) Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before();
        Object result = method.invoke(this.target,args);
        after();
        return result;
    }

    private void after() {
        System.out.println("双方同意,开始交往");
    }

    private void before() {
        System.out.println("我是媒婆,已经收集到你的需求,开始物色");
    }
}

public class Zhangsan implements IPerson {

    public void findLove() {
        System.out.println("张三要求:肤白貌美大长腿");
    }
}

public class ZhaoLiu implements IPerson {

    public void findLove() {
        System.out.println("赵六要求:有车有房学历高");
    }
}


public class Test {
    public static void main(String[] args) {
        try {
            IPerson obj = (IPerson)new JdkMeipo().getInstance(new Zhangsan());
            obj.findLove();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

动态代理实例:切换数据源
JDK动态代理生成对象的步骤如下:
(1)获取被代理对象的引用,并且获取它的所有接口,反射获取。
(2)JDK动态代理类重新生成一个新的类,同时新的类要实现被代理类实现的所有接口。
(3)动态生成Java代码,新加的业务逻辑方法由一定的逻辑代码调用(在代码中体现)。
(4)编译新生成的Java代码.class文件。
(5)重新加载到JVM中运行。

3.cglib动态代理

public class CGlibMeipo implements MethodInterceptor {

    public Object getInstance(Class<?> clazz) throws Exception{
        //相当于Proxy,代理的工具类
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        return enhancer.create();
    }

    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        before();
        Object obj = methodProxy.invokeSuper(o,objects);
        after();
        return obj;
    }

    private void before(){
        System.out.println("我是媒婆,我要给你找对象,现在已经确认你的需求");
        System.out.println("开始物色");
    }

    private void after(){
        System.out.println("OK的话,准备办事");
    }
}

public static void main(String[] args) {

        try {
            Customer obj = (Customer) new CGlibMeipo().getInstance(Customer.class);
            obj.findLove();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

public class Customer {

    public void findLove(){
        System.out.println("儿子要求:肤白貌美大长腿");
    }
}

装饰器模式(包装器模式)

指在不改变原有对象的基础上,动态地给一个对象添加一些额外的职责。
就增加功能来说,装饰器模式相比生成子类更为灵活
煎饼类

public class Battercake {

    protected String getMsg(){
        return "煎饼";
    }

    public int getPrice(){
        return 5;
    }

}
加鸡蛋的煎饼
public class BattercakeWithEgg extends Battercake{

    protected String getMsg(){
        return super.getMsg() + "+1个鸡蛋蛋";
    }

    public int getPrice(){
        return super.getPrice() + 1;
    }

}

加鸡蛋和香肠的煎饼
public class BattercakeWithEggAndSauage extends BattercakeWithEgg{

    protected String getMsg(){
        return super.getMsg() + "+1根香肠";
    }

    public int getPrice(){
        return super.getPrice() + 2;
    }

}
使用
public static void main(String[] args) {
        Battercake battercake = new Battercake();
        System.out.println(battercake.getMsg() + ",总价:" + battercake.getPrice());

        BattercakeWithEgg battercakeWithEgg = new BattercakeWithEgg();
        System.out.println(battercakeWithEgg.getMsg() + ",总价:" + battercakeWithEgg.getPrice());

        BattercakeWithEggAndSauage battercakeWithEggAndSauage = new BattercakeWithEggAndSauage();
        System.out.println(battercakeWithEggAndSauage.getMsg() + ",总价:" + battercakeWithEggAndSauage.getPrice());
    }

如果需要灵活添加鸡蛋和香肠,如果直接增加子类,其实不太灵活,这个时候可以就可以使用装饰器模式

创建一个煎饼抽象类
public abstract class Battercake {
    protected abstract String getMsg();
    protected abstract int getPrice();

}
创建一个基本的煎饼
public class BaseBattercake extends Battercake {
    protected String getMsg() {
        return "煎饼";
    }

    protected int getPrice() {
        return 5;
    }
}
创建一个扩展套餐的抽象类,继承煎饼抽象类
public abstract class BattercakeDecorator extends Battercake {

    private Battercake battercake;

    public BattercakeDecorator(Battercake battercake) {
        this.battercake = battercake;
    }

    public abstract void doSomething();

    protected String getMsg() {
        return this.battercake.getMsg();
    }

    protected int getPrice() {
        return this.battercake.getPrice();
    }
}

创建鸡蛋装饰器类
public class EggDecorator extends BattercakeDecorator {
    public EggDecorator(Battercake battercake) {
        super(battercake);
    }
    public void doSomething() {
    }
    @Override
    protected String getMsg() {
        return super.getMsg() + "1个鸡蛋";
    }

    @Override
    protected int getPrice() {
        return super.getPrice() + 1;
    }
}
创建香肠装饰器类
public class SausageDecorator extends BattercakeDecorator {
    public SausageDecorator(Battercake battercake) {
        super(battercake);
    }
    public void doSomething() {
    }
    @Override
    protected String getMsg() {
        return super.getMsg() + "1根香肠";
    }

    @Override
    protected int getPrice() {
        return super.getPrice() + 2;
    }
}
测试
public static void main(String[] args) {

        Battercake battercake;
        battercake = new BaseBattercake();
        battercake = new EggDecorator(battercake);
        battercake = new EggDecorator(battercake);
        battercake = new SausageDecorator(battercake);
        System.out.println(battercake.getMsg() + ",总价:" + battercake.getPrice());
    }
  • 在jdk中io流这一块用的装饰器比较多
  • 代理模式和装饰器模式的区别
    简单来讲,假设现在小明想租房,那么势必会有一些事务发生:房源搜索、联系房东谈价格等。
    假设按照代理模式进行思考,那么小明只需找到一个房产中介,让他去做房源搜索、联系房东谈价格这些事情,
    小明只需等待通知然后付中介费就行了。
    而如果采用装饰器模式进行思考,因为装饰器模式强调的是自身功能扩展,
    也就是说,如果要找房子,小明自身就要增加房源搜索能力扩展、联系房东谈价格能力扩展,
    通过相应的装饰器,提升自身能力,一个人做完所有的事情。

享元模式

享元模式把一个对象的状态分成内部状态和外部状态,内部状态是不变的,外部状态是变化的;然后通过共享不变的部分,达到减少对象数量并节约内存的目的
常用的就是数据库连接池

  • jdk中的String用到了享元模式
  • Integer对128内对象进行缓存,也用到享元模式

组合模式

当子系统与其内各个对象层次呈树形结构时,可以使用组合模式让子系统内各个对象层次的行为操作具备一致性
它的宗旨是通过将单个对象(叶子节点)和组合对象(树枝节点)用相同的接口进行表示,使得客户对单个对象和组合对象的使用具有一致性
组合模式一般用来描述整体与部分的关系,它将对象组织到树形结构中,顶层的节点被称为根节点,
根节点下面可以包含树枝节点和叶子节点,树枝节点下面又可以包含树枝节点和叶子节点


  1. 透明组合模式
    透明组合模式是把所有公共方法都定义在Component中,这样做的好处是客户端无须分辨叶子节点和树枝节点,它们具备完全一致的接口
    eg:实现课程目录结构
定义节点的公共部分
public abstract class CourseComponet {

    public void addChild(CourseComponet componet){
        throw new UnsupportedOperationException("不支持添加操作");
    }

    public void removeChild(CourseComponet componet){
        throw new UnsupportedOperationException("不支持删除操作");
    }

    public String getName(CourseComponet componet){
        throw new UnsupportedOperationException("不支持获取名称操作");
    }

    public double getPrice(CourseComponet componet){
        throw new UnsupportedOperationException("不支持获得价格操作");
    }

    public void print(){
        throw new UnsupportedOperationException("不支持打印操作");
    }

}
课程类
public class Course extends CourseComponet {

    private String name;
    private double price;

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

    @Override
    public String getName(CourseComponet componet) {
        return this.name;
    }

    @Override
    public double getPrice(CourseComponet componet) {
        return this.price;
    }

    @Override
    public void print() {
        System.out.println(name + "(¥" + price + "元)");
    }
}

课程目录
public class CoursePackage extends CourseComponet {
    private List<CourseComponet> itmes = new ArrayList<CourseComponet>();

    private String name;
    private Integer level;

    public CoursePackage(String name, Integer level) {
        this.name = name;
        this.level = level;
    }


    @Override
    public void addChild(CourseComponet componet) {
        itmes.add(componet);
    }

    @Override
    public void removeChild(CourseComponet componet) {
        itmes.remove(componet);
    }

    @Override
    public String getName(CourseComponet componet) {
        return this.name;
    }

    @Override
    public void print() {
        System.out.println(this.name);

        for (CourseComponet c : itmes) {
            if(this.level != null){
                for (int i = 0; i < this.level; i++) {
                    System.out.print("   ");
                }
                for (int i = 0; i < this.level; i++) {
                    if(i==0){
                        System.out.print("+");
                    }
                    System.out.print("-");
                }
            }

            c.print();
        }

    }
}

测试
public class Test {
    public static void main(String[] args) {
        System.out.println("============透明的组合模式==============");

        CourseComponet javaBase = new Course("Java入门课程",8280);
        CourseComponet ai = new Course("人工智能",5000);

        CourseComponet packageCourse = new CoursePackage("Java架构师课程",2);

        CourseComponet design = new Course("Java设计模式",1500);
        CourseComponet source = new Course("源码分析",2000);
        CourseComponet softSkill = new Course("软技能",3000);

        packageCourse.addChild(design);
        packageCourse.addChild(source);
        packageCourse.addChild(softSkill);

        CourseComponet catalog = new CoursePackage("咕泡课程目录",1);
        catalog.addChild(javaBase);
        catalog.addChild(ai);
        catalog.addChild(packageCourse);

        catalog.print();

    }
}

2.安全组合模式
安全组合模式只规定系统各个层次的最基础的一致行为,而把组合(节点)本身的方法(管理子类对象的添加、删除等)放到自身当中
使用安全组合模式实现无限级文件系统

public abstract class Direcotry {
    protected String name;

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

    public abstract void show();
}

public class File extends Direcotry {
    public File(String name) {
        super(name);
    }

    public void show() {
        System.out.println(this.name);
    }
}

public class Folder extends Direcotry {

    private List<Direcotry> dirs;

    private Integer level;

    public Folder(String name,Integer level) {
        super(name);
        this.level = level;
        this.dirs = new ArrayList<Direcotry>();
    }

    public void show() {
        System.out.println(this.name);

        for (Direcotry c : dirs) {
            if(this.level != null){
                for (int i = 0; i < this.level; i++) {
                    System.out.print("   ");
                }
                for (int i = 0; i < this.level; i++) {
                    if(i==0){
                        System.out.print("+");
                    }
                    System.out.print("-");
                }
            }

            c.show();
        }
    }

    public boolean add(Direcotry dir){
        return this.dirs.add(dir);
    }

    public boolean remove(Direcotry dir){
        return this.dirs.remove(dir);
    }

    public Direcotry get(int index){
        return this.dirs.get(index);
    }

    public void list(){
        for (Direcotry dir : dirs) {
            System.out.println(dir.name);
        }
    }
}

public class Test {
    public static void main(String[] args) {
        System.out.println("==========安全模式的写法=============");

        Folder im = new Folder("即时聊天",2);


        File qq = new File("QQ.exe");
        File wx = new File("微信.exe");

        Folder sns = new Folder("社交",3);
        Folder love = new Folder("两性",4);
        Folder normal = new Folder("职场",4);
        Folder high = new Folder("高端",5);
        Folder low = new Folder("低端",5);


        File momo = new File("Momo.exe");
        love.add(momo);

        File maimai = new File("Maimai.exe");
        low.add(maimai);

        File boss = new File("Boss直聘.exe");
        high.add(boss);

        normal.add(high);
        normal.add(low);

        sns.add(love);
        sns.add(normal);

        im.add(qq);
        im.add(wx);
        im.add(sns);


        Folder office = new Folder("办公软件",2);

        File word = new File("Word.exe");
        File ppt = new File("PowerPoint.exe");
        File excel = new File("Excel.exe");


        office.add(word);
        office.add(ppt);
        office.add(excel);

        Folder root = new Folder("D盘",1);

        root.add(im);
        root.add(office);

        System.out.println("=============show()=============");
        root.show();

        System.out.println("=============list()=============");
        root.list();
    }
}
  • HashMap中的putAll方法用到了组合模式
  • mybatis解析xml生成sql的过程用到了组合模式

适配器模式

它的功能是将一个类的接口变成客户端所期望的另一种接口,从而使原本因接口不匹配而导致无法在一起工作的两个类能够一起工作

public class AC220 {
    public int outputAC220V(){
        int output = 220;
        System.out.println("输出电压" + output + "V");
        return output;
    }
}

public interface DC5 {
    int output5V();
}

public class PowerAdapter extends AC220 implements DC5 {
    public int output5V() {
        int adapterInput = super.outputAC220V();
        int adapterOutput = adapterInput / 44;
        System.out.println("使用Adapter输入AC" + adapterInput + "V,输出DC" + adapterOutput + "V");
        return adapterOutput;
    }
}

public static void main(String[] args) {
        DC5 adapter = new PowerAdapter();
        adapter.output5V();
    }
  • 在Spring中,适配器模式应用得非常广泛
    例如Spring AOP中的AdvisorAdapter类
    它有3个实现类:MethodBeforeAdviceAdapter、AfterReturningAdviceAdapter和ThrowsAdviceAdapter

桥接模式

指将抽象部分与具体实现部分分离,使它们都可以独立地变化

public interface IMessage {
    //发送消息的内容和接收人
    void send(String message,String toUser);
}
发送邮件
public class EmailMessage implements IMessage {
    public void send(String message, String toUser) {
        System.out.println("使用邮件消息发送" + message + "给" + toUser);
    }
}
发送短信
public class SmsMessage implements IMessage {
    public void send(String message, String toUser) {
        System.out.println("使用短信消息发送" + message + "给" + toUser);
    }
}

发送消息抽象类
public abstract class AbastractMessage {
    private IMessage message;

    public AbastractMessage(IMessage message) {
        this.message = message;
    }
    void sendMessage(String message,String toUser){
        this.message.send(message,toUser);
    }
}
发送正常的消息
public class NomalMessage extends AbastractMessage {
    public NomalMessage(IMessage message) {
        super(message);
    }
}
发送加急的消息
public class UrgencyMessage extends AbastractMessage {
    public UrgencyMessage(IMessage message) {
        super(message);
    }

    void sendMessage(String message, String toUser){
        message = "【加急】" + message;
        super.sendMessage(message,toUser);
    }

    public Object watch(String messageId){
        return null;
    }
}
使用
public static void main(String[] args) {
        IMessage message = new SmsMessage();
        AbastractMessage abastractMessage = new NomalMessage(message);
        abastractMessage.sendMessage("加班申请","王总");
        //加急消息
        message = new EmailMessage();
        abastractMessage = new UrgencyMessage(message);
        abastractMessage.sendMessage("加班申请","王总");
    }

采用桥接模式解耦了“消息类型”和“消息紧急程度”这两个独立变化的维度

> 行为型设计模式

委派模式

老板给项目经理下达任务,项目经理会根据实际情况给每个员工都分配工作任务,待员工把工作任务完成之后,再由项目经理向老板汇报工作进度和结果。再比如,我们经常写授权委托书,授权他人代办事务

public interface IEmployee {
    void doing(String task);
}

public class EmployeeA implements IEmployee {
    protected String goodAt = "编程";
    public void doing(String task) {
        System.out.println("我是员工A,我擅长" + goodAt + ",现在开始做" +task + "工作");
    }
}

public class EmployeeB implements IEmployee {
    protected String goodAt = "平面设计";
    public void doing(String task) {
        System.out.println("我是员工B,我擅长" + goodAt + ",现在开始做" +task + "工作");
    }
}

public class Leader implements IEmployee {

    private Map<String,IEmployee> employee = new HashMap<String,IEmployee>();

    public Leader(){
        employee.put("爬虫",new EmployeeA());
        employee.put("海报图",new EmployeeB());
    }

    public void doing(String task) {
        if(!employee.containsKey(task)){
            System.out.println("这个任务" +task + "超出我的能力范围");
            return;
        }
        employee.get(task).doing(task);
    }
}

public class Boss {
    public void command(String task,Leader leader){
        leader.doing(task);
    }
}

public class Test {
    public static void main(String[] args) {
        new Boss().command("海报图",new Leader());
        new Boss().command("爬虫",new Leader());
        new Boss().command("卖手机",new Leader());
    }
}
  • jvm中的双亲委派模式

  • spring源码中的委派模式

    针对不同的节点类型,完成Bean的注册操作

  • springmvc中的DispatcherServlet实现委派模式

模板方法模式

封装了一个固定流程,该流程由几个步骤组成,具体步骤可以由子类进行不同的实现,从而让固定的流程产生不同的结果
比如入职流程:填写入职登记表→打印简历→复印学历证书→复印身份证→签订劳动合同→建立花名册→办理工牌→安排工位等

策略模式

策略模式使用的就是面向对象的继承和多态机制,从而实现同一行为在不同的场景下具备不同的实现。
通用逻辑写在抽象类中

public abstract class Payment {

    public abstract String getName();

    //通用逻辑放到抽象类里面实现
    public MsgResult pay(String uid, double amount){
        //余额是否足够
        if(queryBalance(uid) < amount){
            return new MsgResult(500,"支付失败","余额不足");
        }
        return new MsgResult(200,"支付成功","支付金额" + amount);
    }

    protected abstract double queryBalance(String uid);
}

各种实现类

public class AliPay extends Payment {
    public String getName() {
        return "支付宝";
    }

    protected double queryBalance(String uid) {
        return 900;
    }
}

public class JDPay extends Payment {
    public String getName() {
        return "京东白条";
    }

    protected double queryBalance(String uid) {
        return 500;
    }
}

public class UnionPay extends Payment {
    public String getName() {
        return "银联支付";
    }

    protected double queryBalance(String uid) {
        return 120;
    }
}

public class WechatPay extends Payment {
    public String getName() {
        return "微信支付";
    }

    protected double queryBalance(String uid) {
        return 263;
    }
}


然后将各种实现都实例化,保存到map中

public class PayStrategy {
    public static  final String ALI_PAY = "AliPay";
    public static  final String JD_PAY = "JdPay";
    public static  final String WECHAT_PAY = "WechatPay";
    public static  final String UNION_PAY = "UnionPay";
    public static  final String DEFAULT_PAY = ALI_PAY;

    private static Map<String,Payment> strategy = new HashMap<String,Payment>();

    static {
        strategy.put(ALI_PAY,new AliPay());
        strategy.put(JD_PAY,new JDPay());
        strategy.put(WECHAT_PAY,new WechatPay());
        strategy.put(UNION_PAY,new UnionPay());
    }

    public static Payment get(String payKey){
        if(!strategy.containsKey(payKey)){
            return strategy.get(DEFAULT_PAY);
        }
        return strategy.get(payKey);
    }
}

public class Order {
    private String uid;
    private String orderId;
    private double amount;

    public Order(String uid, String orderId, double amount) {
        this.uid = uid;
        this.orderId = orderId;
        this.amount = amount;
    }

    public MsgResult pay(){
        return pay(PayStrategy.DEFAULT_PAY);
    }

    public MsgResult pay(String payKey){
        Payment payment = PayStrategy.get(payKey);
        System.out.println("欢迎使用" + payment.getName());
        System.out.println("本次交易金额为" + amount + ",开始扣款");
        return payment.pay(uid,amount);
    }
}

最后调用

public class Test {
    public static void main(String[] args) {
        Order order = new Order("1","2020031401000323",324.5);
        System.out.println(order.pay(PayStrategy.ALI_PAY));
    }
}
posted @ 2021-08-05 17:24  余***龙  阅读(88)  评论(0编辑  收藏  举报