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


    七大软件设计原则

    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("加班申请","王总");
        }
    

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

  • 相关阅读:
    表单校验神器
    插入排序
    数组去重的几种常使用的方式
    day44 mysql高级部分内容
    day43 多表查询和pymysql
    day42 字段的增删改查详细操作
    day41 mysql详细操作
    day40 mysql数据类型
    day39 mysql数据库基本操作
    day37 异步回调和协程
  • 原文地址:https://www.cnblogs.com/Baronboy/p/15104346.html
Copyright © 2020-2023  润新知