设计模式笔记(一)—— 设计原则与工厂方法模式详解

设计模式学习笔记,感谢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):一个软件实体如果适用一个父类,那一定适用其子类,所有引用父类的地方必须透明地使用其子类对象,子类对象能够替换父类对象,而程序逻辑不变;

    子类可以扩展父类的功能,但不能改变父类原有的功能:

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

    约束继承泛滥,开闭原则的一种体现;加强程序的健壮性,变更时可做好更好的兼容性,提高程序的维护性、扩展性,降低需求变更引入的风险。

  • 合成/聚合复用原则(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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值