读书笔记----软件设计原则、设计模式

这个作业属于哪个课程 https://edu.cnblogs.com/campus/gdgy/2021Softwarecodedevelopmenttechnology
这个作业要求在哪 https://edu.cnblogs.com/campus/gdgy/2021Softwarecodedevelopmenttechnology/homework/11833
这个作业的目标 了解设计原则与设计模式的原理与应用

相应的贴子:
装饰者模式 https://www.cnblogs.com/of-fanruice/p/11565679.html---------转载
工厂模式 https://www.cnblogs.com/yssjun/p/11102162.html---------转载
代理模式 https://www.cnblogs.com/daniels/p/8242592.html--------转载

浅谈我对以上三种设计模式的理解与在学习软件开发中的应用

装饰者模式:

  在实际的开发中,我们不可避免地会使用继承来拓展细化类的功能。但是越细化,类的继承子类会越来越多,出现类的继承爆炸。不利于开发和维护 ,如下图:

  装饰者模式通过将责任动态的追加到继承的子类中来动态的拓展和细化子类的功能,解决了上述类继承爆炸的现象。其大致的设计原理如图:

装饰者模式的特点:
* 装饰者与被装饰者有相同的超类
* 装饰者可以在被装饰的对象实例化前或实例化后将下自己的行为附加到被装饰者身上,使被装饰者有了特定的行为
* 一个对象可以被多个装饰类吧包装,具备多个行为
* 拓展细化类时,只需要根据需求拓展装饰类,再通过装饰类对实例对象进行包装即可,可以根据需要无限的拓展细化实例对象

模拟装饰者的相关代码:

超类:Person
package Super;


/**
 * 超类,代表人类
 * @author one者天下
 * @date 2021-03-14 15:56
 */
public abstract class Person {
    // 姓名
    public String name = null;


    public String description(){
        return name;
    }
}

实体类A:
package Super.Child;

import Super.Person;

/**
 * 姓名为A的人
 * @author one者天下
 * @date 2021-03-14 16:18
 */
public class A extends Person {

    public A() {
        this.name = "A";
    }
}
实体类B:
package Super.Child;

import Super.Person;

/**
 * 姓名为B的人
 * @author one者天下
 * @date 2021-03-14 16:20
 */
public class B extends Person {

    public B() {
        this.name = "B";
    }
}
身份描述类:

学生身份:
package Super.Identity.Impl;

import Super.Identity.Identity;
import Super.Person;

/**
 * @author one者天下
 * @date 2021-03-14 16:04
 */
public class Student extends Identity {

    Person person;

    public Student(Person person) {
        this.person = person;
    }

    @Override
    public String description() {
        return person.description() + " 学生";
    }
}
小学生:
package Super.Identity.Impl;

import Super.Identity.Identity;
import Super.Person;

/**
 * @author one者天下
 * @date 2021-03-14 16:22
 */
public class Primary extends Identity {

    Person person;

    public Primary(Person person) {
        this.person = person;
    }

    @Override
    public String description() {
        return person.description() + " 小学生";
    }
}
中国国籍:
package Super.Identity.Impl;

import Super.Identity.Identity;
import Super.Person;

/**
 * @author one者天下
 * @date 2021-03-14 16:27
 */
public class Chinese extends Identity {

    Person person;

    public Chinese(Person person) {
        this.person = person;
    }

    @Override
    public String description() {
        return person.description() + " 中国国籍";
    }
}
日本国籍:
package Super.Identity.Impl;

import Super.Identity.Identity;
import Super.Person;

/**
 * @author one者天下
 * @date 2021-03-14 16:29
 */
public class Japanese extends Identity {

    Person person;

    public Japanese(Person person) {
        this.person = person;
    }

    @Override
    public String description() {
        return person.description() + " 日本国籍";
    }
}

模拟测试:
package test;

import Super.Child.A;
import Super.Child.B;
import Super.Identity.Impl.Chinese;
import Super.Identity.Impl.Japanese;
import Super.Identity.Impl.Primary;
import Super.Identity.Impl.Student;
import Super.Person;

/**
 * 表现装饰者模式
 * @author one者天下
 * @date 2021-03-14 16:30
 */
public class Test {

    public static void main(String[] args) {
        // 构造一个日本国籍的小学生B
        Person japanesePersonB = new Japanese(new Primary(new B()));
        System.out.println(japanesePersonB.description());
        // 构造一个中国国籍的学生B
        Person chinesePersonB = new Chinese(new Student(new B()));
        System.out.println(chinesePersonB.description());
        // 构造一个中国国籍的小学生A
        Person chinesePersonA = new Chinese(new Primary(new A()));
        System.out.println(chinesePersonA.description());
    }
}

执行结果:

工厂模式:

工厂模式是用于创建对象,能有效降低解程序的耦合。以往创建实例对象俺的方式往往采用直接创建的方式进行创建。
但实际开发中,这样的创建对像的方式往往会存在类与类之间的依赖严重的现象。依赖的模块若不在相应的路径下会在编译期间产生编译不通过的问题,降低程序的开发效率
工厂模式的设计原理,是将创建对象的职能从原来的程序中解放出来,将创建对象和管理对象的功能完全交给工厂管理,这样的好处是解决了模块与模块之间的依赖关系,
使得程序开发者能将精力完全集中于业务逻辑功能的实现。
在Java的spring框架中,就采用工厂模式,将创建的对象存储在IOC容器中,若是业务需要添加新的类,则在相应的
xml配置文件中配置类的全限定类名与相应的id,spring的工厂会将再次扫描xml配置文件,将创建的对象存入IOC容器中,从而避免了去修改业务逻辑的代码,不需要将项目重新
部署上线,降低了程序间的耦合度,提高程序的开发效率。

通过简易的代码模拟一个生产对象的工厂和创建对象的过程

实现原理:
将对象的id和全限定类名在properties文件中配置,工厂将读取配置文件并创建对象,存放在一个以name-Object键值对形式的Map集合中。
模拟的代码实现:
bean.properties文件的相关内容:
<---将通过工厂创建的对象--->
user=com.spring.bean.User
account=com.spring.bean.Account 

factory:
package com.spring.factory;

import java.io.InputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
 * 一个生产JavaBean的工厂,用于程序模块之间的解耦----->使用单例模式
 * 将创建的bean对象封装在Map实例对象中
 * @author one者天下
 * @date 2021-03-02 22:11
 */
public class JavaBeanFactory {

    /**
     * 读取配置信息的流
     */
    private static Properties properties;
    /**
     * 存储单例模式下创建的对象
     */
    private static Map<String,Object> beans;

    /**
     * 创建一个读取配置JavaBean的读取流
     */
    static {
        try {
            properties = new Properties();
            InputStream inputStream = JavaBeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
            properties.load(inputStream);
            // 获取配置文件中所以的键值,返回一个枚举对象
            Enumeration<Object> keys = properties.keys();
            beans = new HashMap<>();
            // 遍历枚举对象
            while (keys.hasMoreElements()){
                // 获取枚举对象中的value值
                String beanName = keys.nextElement().toString();
                String beanPath = properties.getProperty(beanName);
                // 根据类的全限定类名创建反射实例
                Object bean = Class.forName(beanPath).newInstance();
                // 将创建的bean对象存储在Map实例对象
                beans.put(beanName,bean);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * 获取javaBean对象
     * @param BeanName 需要获取的对象对应的类名
     * @return 返回一个Object类型的对象实例
     */
    public static Object getBean(String BeanName){
        return beans.get(BeanName);
    }
}
实体类User:
package com.spring.bean;

import java.io.Serializable;

/**
 * 一个用户信息表
 * @author one者天下
 * @date 2021-03-02 22:08
 */

public class User implements Serializable {

    private String name;
    private String sex;
    private String password;
    private Account account;

    public User() {
    }

    public Account getAccount() {
        return account;
    }

    public void setAccount(Account account) {
        this.account = account;
    }

    public String getName() {
        return name;
    }

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

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", sex='" + sex + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}
测试代码:
package com.spring.test;

import com.spring.bean.User;
import com.spring.factory.JavaBeanFactory;
import org.junit.Test;

/**
 * @author one者天下
 * @date 2021-03-14 19:52
 */
public class test {
    @Test
    public void Test(){
        User user = (User) JavaBeanFactory.getBean("user");
        user.setSex("男");
        user.setName("憨憨");
        user.setPassword("3118005030");
        System.out.println(user);
    }
}

执行结果:

代理模式:

顾名思义,给某个对象创建一个代理对象,替代该对象去执行相应的行为和动作。类似中介。
*作用:*
隔离:避免对象直接引用委托对象,代理对象像中介一样,处于用户类与委托类之间,进行双方的隔离与调和。
增强:代理类可以对被代理对象进行方法的增强,增加被代理对象方法的功能,比如给被代理对象的方法进行事务就控制等等。
提高代码的可重用性:使用代理模式后,若是想给被代理对象的方法进行优化,可以通过代理对象对被代理对象的方法进行增强,避免了大规模的修改源码。
缓解程序的耦合度

其原理的简易类图如下:

代理模式主要分静态代理与动态代理两种模式;

简易的模拟代理模式的方法增强(基于实现接口的子类的动态代理)

源码如下:
/**
 *
 * 模拟代理类实现的生产者接口
 * @author one者天下
 * @date 2021-03-14 20:26
 */
public interface Producers {
    /**
     * 打印输出被调用
     */
    void printFun();
}
/**
 * 生产者,模拟被代理类
 * @author one者天下
 * @date 2021-03-14 20:24
 */
public class ProducersImpl implements Producers {

    @Override
    public void printFun(){
        System.out.println("生产者类被调用了");
    }
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 *
 * 模拟代理模式,对Producer的printFun()的增强
 * @author one者天下
 * @date 2021-03-14 20:28
 */
public class ProxyTest {
    public static void main(String[] args) {
        Producers pr = (Producers) Proxy.newProxyInstance(Producers.class.getClassLoader(), ProducersImpl.class.getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("生产者的printFun()被增强了");
                return method.invoke(new ProducersImpl());
            }
        });
        System.out.println("======未使用代理模式=========");
        Producers producers = new ProducersImpl();
        producers.printFun();
        System.out.println("======使用了代理模式=========");
        pr.printFun();
    }
}

执行结果:

博客园的后台编辑界面:

心得体验:

程序规模越大,程序的耦合越来越强,利用这些设计模式可以在一定程度上降低程序的耦合度,提高程序的开发。
另外,提高代码的可重用性也是极其必要的,而代码的抽取又与这些设计模式密不可分,可见学习设计模式的重要性。
应用设计模式也是学习的重点,了解原理后要将其应用在实际的开发中。
学习完设计模式后,在下次开发中,应该在实际开发前就架构好整体的设计模式,这样可以极大的缩短整个项目的开发生命周期,也有利于项目的后续维护。
现在我接触到的设计模式只是冰山一角,仅仅这些还远远达不到软件开发的需要,因此会随着接下来的就开发中不断地汲取和应用设计原则和设计模式。

人生苦短,我用设计!

posted @ 2021-03-14 21:01  Z-G-Love  阅读(92)  评论(0编辑  收藏  举报