精华内容
下载资源
问答
  • Hibernate是一开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO(plain ordinary java object简单的java对象)与数据库表建立映射关系,是一全自动的orm(object relational ...

    Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO(plain ordinary java object简单的java对象)与数据库表建立映射关系,是一个全自动的orm(object relational mapping关系对象模型)框架,hibernate可以自动生成SQL语句,自动执行,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。 Hibernate可以应用在任何使用JDBC的场合,既可以在Java的客户端程序使用,也可以在Servlet/JSP的Web应用中使用,最具革命意义的是,Hibernate可以在应用EJB的JaveEE架构中取代CMP,完成数据持久化的重任。

    6.1 框架简介

    6.1.1 Hibernate框架框架简介

    1.Hibernate框架的概念

    所谓持久化(persistence),是指把数据(内存中的对象)保存到可永久保存的存储设备中(如磁盘)。持久化的主要应用是将内存中的对象存储在关系型的数据库中,当然也可以存储在磁盘文件、xml文件中等。持久化是将程序数据在持久状态和瞬时状态间转换的机制。jdbc、IO都是持久化机制。

    持久化的典型三层架构为表示层、业务层和持久层,Hibernate可以将对象自动地生成数据库中的信息,使得开发更加面向对象。

    Hibernate可以在java的任何项目中使用,而不仅仅是web项目。Hibernate不需要类似于tomcat这些容器的支持,可以直接通过一个main方法进行测试,代码量大大减少。

    映射就是对象关系映射,是指将程序中的对象数据保存到数据库中,同时将数据库中的数据读入对象中,开发人员只对对象操作就可以完成对数据库数据的操作。

    2.Hibernate框架的语言特点

    1)将对数据库的操作转换为对Java对象的操作来简化开发

    2)提供线程和进程两个级别的缓存来提升应用程序性能

    3)有丰富的映射关系将Java对象之间的关系转换为数据表之间的关系

    4)屏蔽不同数据库实现之间的差异,只需要通过“方言”的形式指定当前使用的数据库,就可以根据底层数据库的实际情况生成适合的SQL语句

    5)非侵入式:Hibernate不要求持久化类实现任何接口或继承任何类,POJO即可

    6.1.2 POJO简介

    POJO实质上可以理解为简单的Java对象,有时也被称为data对象。POJO的主要作用是方便程序员使用数据库中的数据表,可以很方便地将POJO类当做对象来进行使用,当然也可以调用它的get()和set()方法。POJO对象同样也为配置Hibernate框架带来了极大的方便。

    如果项目中使用了Hibernate框架,用一个关联的xml文件,使对象与数据库中的表对应,对象属性与表中的字段相对应。

    POJO一般使用private参数作为对象的属性,然后针对每个属性定义了getXXX()、和setXXX()方法作为访问的接口。

    举例:User.java

    public class User{
    private long id;
    private String name;
    public void setId(long id){
    this.id=id;
    }
    public void setName( String name){
    this.name=name;
    }
    public long getId(){
    return id;
    }
    public String getName(){
    return name;
    }
    }

    从例子可以看出,POJO就是一个普通的Java类对象,没有任何特定的规则,不与任何特定框架的接口绑定,一般也没有构造方法。

    下面介绍一下POJO与JavaBean的区别与联系:

    JavaBean的严格定义应为:是一种Java语言写成的可重用组件。它的方法命名、构造及行为必须符合特定的约定:这个类是公有类,并且必须有一个public默认构造函数。类的属性使用getter和setter来访问,其他方法遵从标准命名规范。这个类应是可序列化的。因为这些要求主要是靠约定而不是靠实现接口,所以很多开发者把JavaBean看作是遵从特定命名规定的POJO。其实这些规定的主要原因是:JavaBean一般是提供给容器(框架)使用的。

    EntityBean是OR映射中对应表的每行信息封装的实体类。当然,它符合JavaBean的约定,一般只有属性,没有方法。

    6.1.3 Hibernate的核心接口

    1. Hibernate的核心API

    Hibernate的核心API共有6个,如下图。通过这些接口,可以对持久化对象进行存取和事物控制等操作。

    (1)session接口负责执行被持久化对象的增加、读取查询、更新及删除操作(create、retrieve、update、delete,简称CRUD操作),包含很多常见的SQL语句。需要注意的是,session对象是非线程安全的,因此在设计中最好一个线程只创建一个session对象。同时Hibernate的session不同于JSP应用中的HTTPSession。

    (2)SessionFactory接口

    负责初始化Hibernate。它充当数据存储源的代理,并负责创建session对象,这里用到了工厂模式。需要注意的是,SessionFactory并不是轻量级的,因为一般情况下,一个项目只要一个SessionFactory即可,当需要操作多个数据库时,可以为每个数据库指定一个SessionFactory。

    (3)Transaction接口

    是一个可选的API,这是对实际事务实现的一个统一抽象,这些实现包括JDBC的事务,JTA的UserTransactiion,甚至可以是CORBA(通过对象请求代理体系结构)事务。这个接口的设计,是为了让开发者能够使用一个统一的事务操作界面,是的自己的项目可以在不同的环境和容器之间方便地移植。

    一个典型的事务应该使用下面的形式,beginTransaction()到commit()之间的代码处在同一事务:beginTransaction()开启事务;commit()提交事务;rollback()在发生异常时回滚事务。

    举例:1)session使用sessionFactory.openSession()方式取得,典型代码如下

    Transaction tx=null;
    try{
    tx=session.beginTransaction();
    //做某些处理
    tx.commit();
    }catch(Runtime Exception e){
    if(tx!=null)
    tx.rollback();
    throw e;
    }finally{
    sssion.close();
    }

    2)session使用sessionFactory.getCurrentSession()方式取得,典型代码如下

    Transaction tx=null;
    try{
    tx=session.beginTransaction();
    //做某些处理
    tx.commit();
    }catch(Runtime Exception e){
    
    tx.rollback();
    throw e;
    }

    (4)Query接口

    负责对数据库及持久对象进行查询,它可以有两种表达方式:HQL或者本地数据库的SQL语句。query经常被用来绑定查询参数、限制查询记录数量,并最终执行查询操作。

    (5)criteria接口

    允许创建并执行面向对象的标准化查询,是轻量级的,不能在session之外使用。

    (6)configuration类

    负责配置和启动hibernate。在hibernate的启动过程中,configuration类的实例首先定位映射文档的位置,读取这些配置,然后创建一个sessionFactory对象,是启动hibernate的第一个对象。

    2.hibernate对象的3种状态

    瞬时对象状态、持久化对象状态和离线对象状态

    1)临时对象状态:使用java 的new命令开辟内存空间的Java对象,也就是普通的Java对象,如果没有变量引用它,则会被Java虚拟机进行自动垃圾回收。临时对象在内存中是孤立存在的,它的意义是携带信息载体,不与数据库中的数据有任何关联。通过session的save()和saveOrUpdate()方法可以把一个临时对象和数据库关联,并把临时对象携带的信息通过配置文件所做的映射插入到数据库中,这个对象就称为持久化对象。

    2)持久化对象状态:持久化对象在数据库中有相应的记录,可以是刚被保存的或者刚被加载的,但都是在相关联的session声明周期中保存这个状态。如果是直接用数据库查询所返回的数据对象,则这些对象和数据库中的字段相关联,具有相同的id,他们马上变成持久化对象。如果一个临时对象被持久化对象引用,也变为持久化对象。

    如果使用delete()方法,持久化对象会变成临时对象,并且删除数据库中相应的记录,这个对象不再和数据库有任何的联系。

    持久化对象总是和session和transaction关联在一起。在一个session中,对持久化对象的操作不会立即写入到数据库中,只有当事务结束时,才真正对数据库进行更新,从而完成持久化对象和数据库的同步。

    当一个session执行close()、clear()或evict()之后,持久化对象就变成离线对象,这时对象的id虽然拥有数据库的识别值,但已经不在hibernate持久层的管理下,与临时对象基本上是一样的,只是多了数据库标识id。没有任何变量引用时,也会被垃圾回收。

    3)离线对象状态:session关闭后,与此session关联的持久化对象就变成离线对象,但还可以对这个对象进行修改。如果离线对象被重新关联到某个新的session上,会转化为持久化对象。

    离线对象拥有用户的标识id,所以通过update()、saveOrUpdate()等方法,可以再次与持久层关联,转化为持久化对象。

     

    展开全文
  • 本文思维导图 使用线程池的优点 线程池提供了一种限制和管理资源(包括执行一任务)。 每线程池还维护一些基本统计信息,例如已完成任务的数量。 1.**降低资源消耗。**通过重复利用已创建的线程降低线程创建和...

    本文思维导图

    alt

    使用线程池的优点

    线程池提供了一种限制和管理资源(包括执行一个任务)。 每个线程池还维护一些基本统计信息,例如已完成任务的数量。

    • 1.**降低资源消耗。**通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
    • 2.**提高响应速度。**当任务到达时,任务可以不需要的等到线程创建就能立即执行。
    • 3.**提高线程的可管理性。**线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。

    Executor 框架结构(主要由三大部分组成)

    • 1.任务
    • 执行任务需要实现的Runnable接口或Callable接口。Runnable接口或Callable接口实现类都可以被ThreadPoolExecutor或ScheduledThreadPoolExecutor执行。(Runnable接口不会返回结果但是Callable接口可以返回结果。后面介绍Executors类的一些方法的时候会介绍到两者的相互转换)
    • 2.执行任务
    • 如下图所示,包括任务执行机制的核心接口Executor ,以及继承自Executor 接口的ExecutorService接口ScheduledThreadPoolExecutor和ThreadPoolExecutor这两个关键类实现了ExecutorService接口。
    • alt
    • 3.获得结果
    • Future接口以及Future接口的实现类FutureTask类。
      当我们把Runnable接口或Callable接口的实现类提交(调用submit方法)给ThreadPoolExecutor或ScheduledThreadPoolExecutor时,会返回一个FutureTask对象。

    Executor 框架的使用示意图

    • alt
    • 1.主线程首先要创建实现Runnable或者Callable接口的任务对象。
    • 2.然后可以把创建完成的Runnable对象直接交给ExecutorService执行
    • 3.如果执行ExecutorService.submit(…),ExecutorService将返回一个实现Future接口的对象
    • 4.最后,主线程可以执行FutureTask.get()方法来等待任务执行完成。主线程也可以执行FutureTask.cancel(boolean mayInterruptIfRunning)来取消此任务的执行。

    ThreadPoolExecutor详解

    • 1.ThreadPoolExecutor类中重要的四个属性
    • alt
    • 2.构造方法
    • alt
        /**
         * 用给定的初始参数创建一个新的ThreadPoolExecutor。
         *
         * @param keepAliveTime 当线程池中的线程数量大于corePoolSize的时候,如果这时没有新的任务提交,
         *                      核心线程外的线程不会立即销毁,而是会等待,直到等待的时间超过了keepAliveTime;
         * @param unit          keepAliveTime参数的时间单位
         * @param workQueue     等待队列,当任务提交时,如果线程池中的线程数量大于等于corePoolSize的时候,把该任务封装成一个Worker对象放入等待队列;
         * @param threadFactory 执行者创建新线程时使用的工厂
         * @param handler       RejectedExecutionHandler类型的变量,表示线程池的饱和策略。
         *                      如果阻塞队列满了并且没有空闲的线程,这时如果继续提交任务,就需要采取一种策略处理该任务。
         *                      线程池提供了4种策略:
         *                      1.AbortPolicy:直接抛出异常,这是默认策略;
         *                      2.CallerRunsPolicy:用调用者所在的线程来执行任务;
         *                      3.DiscardOldestPolicy:丢弃阻塞队列中靠最前的任务,并执行当前任务;
         *                      4.DiscardPolicy:直接丢弃任务;
         */
        public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {
            if (corePoolSize < 0 || maximumPoolSize <= 0 || maximumPoolSize < corePoolSize || keepAliveTime < 0)
                throw new IllegalArgumentException();
            if (workQueue == null || threadFactory == null || handler == null) throw new NullPointerException();
            this.corePoolSize = corePoolSize;
            this.maximumPoolSize = maximumPoolSize;
            this.workQueue = workQueue;
            this.keepAliveTime = unit.toNanos(keepAliveTime);
            this.threadFactory = threadFactory;
            this.handler = handler;
        }
    
    • 3.如何创建ThreadPoolExecutor
    • 1.《阿里巴巴Java开发手册》“并发处理”这一章节,明确指出线程资源必须通过线程池提供,不允许在应用中自行显示创建线程。
      为什么呢?
    使用线程池的好处是减少在创建和销毁线程上所消耗的时间以及系统资源开销,解决资源不足的问题。如果不使用线程池,有可能会造成系统创建大量同类线程而导致消耗完内存或者“过度切换”的问题。
    
    • 2.《阿里巴巴Java开发手册》中强制线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险
    Executors 返回线程池对象的弊端如下:
     FixedThreadPool 和 SingleThreadExecutor : 允许请求的队列长度为 Integer.MAX_VALUE,可能堆积大量的请求,从而导致OOM。
    CachedThreadPool 和 ScheduledThreadPool : 允许创建的线程数量为 Integer.MAX_VALUE ,可能会创建大量线程,从而导致OOM。
    
    • 创建方式一:通过构造方法实现
      alt
    • 创建方式二:通过Executor 框架的工具类Executors来实现
    • 创建三种类型的ThreadPoolExecutor:
    • 1.FixedThreadPool
    • 2.SingleThreadExecutor
    • 3.CachedThreadPool
      alt
    • 4.FixedThreadPool详解
    • FixedThreadPool被称为可重用固定线程数的线程池。通过Executors类中的相关源代码来看一下相关实现:
    /**
         * 创建一个可重用固定数量线程的线程池
         * 在任何时候至多有n个线程处于活动状态
         * 如果在所有线程处于活动状态时提交其他任务,则它们将在队列中等待,
         * 直到线程可用。 如果任何线程在关闭之前的执行期间由于失败而终止,
         * 如果需要执行后续任务,则一个新的线程将取代它。池中的线程将一直存在
         * 知道调用shutdown方法
         *
         * @param nThreads      线程池中的线程数
         * @param threadFactory 创建新线程时使用的factory
         * @return 新创建的线程池
         * @throws NullPointerException     如果threadFactory为null
         * @throws IllegalArgumentException if {@code nThreads <= 0}
         */
        public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
            return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), threadFactory);
        }
    
    • 从上面源代码可以看出新创建的FixedThreadPool的corePoolSize和maximumPoolSize都被设置为nThreads。
    • FixedThreadPool的execute()方法运行示意图:
      alt
    • 图片说明:

    • 1.如果当前运行的线程数小于corePoolSize,则创建新的线程来执行任务;
    • 2.当前运行的线程数等于corePoolSize后,将任务加入LinkedBlockingQueue;
    • 3.线程执行完1中的任务后,会在循环中反复从LinkedBlockingQueue中获取任务来执行;
    • FixedThreadPool使用无界队列 LinkedBlockingQueue(队列的容量为Intger.MAX_VALUE)作为线程池的工作队列会对线程池带来如下影响:

    public LinkedBlockingQueue() {
            this(Integer.MAX_VALUE);
        }
    
    • 1.当线程池中的线程数达到corePoolSize后,新任务将在无界队列中等待,因此线程池中的线程数不会超过corePoolSize;
    • 2.由于1,使用无界队列时maximumPoolSize将是一个无效参数;
    • 3.由于1和2,使用无界队列时keepAliveTime将是一个无效参数;
    • 4.运行中的FixedThreadPool(未执行shutdown()或shutdownNow()方法)不会拒绝任务
    • 5.SingleThreadExecutor详解
    • SingleThreadExecutor是使用单个worker线程的Executor。下面看看SingleThreadExecutor的实现:
        /**
         * 创建使用单个worker线程运行无界队列的Executor
         * 并使用提供的ThreadFactory在需要时创建新线程
         *
         * @param threadFactory 创建新线程时使用的factory
         * @return 新创建的单线程Executor
         * @throws NullPointerException 如果ThreadFactory为空
         */
        public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
            return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), threadFactory));
        }
    
    • 从上面源代码可以看出新创建的SingleThreadExecutor的corePoolSize和maximumPoolSize都被设置为1.其他参数和FixedThreadPool相同。SingleThreadExecutor使用无界队列LinkedBlockingQueue作为线程池的工作队列(队列的容量为Intger.MAX_VALUE)。SingleThreadExecutor使用无界队列作为线程池的工作队列会对线程池带来的影响与FixedThreadPool相同。
    • SingleThreadExecutor的运行示意图
      alt
    • 图片说明:

    • 1.如果当前运行的线程数少于corePoolSize,则创建一个新的线程执行任务;
    • 2.当前线程池中有一个运行的线程后,将任务加入LinkedBlockingQueue
    • 3.线程执行完1中的任务后,会在循环中反复从LinkedBlockingQueue中获取任务来执行;
    • 6.CachedThreadPool详解
    • CachedThreadPool是一个会根据需要创建新线程的线程池。下面通过源码来看看 CachedThreadPool的实现:
    /**
         * 创建一个线程池,根据需要创建新线程,但会在先前构建的线程可用时重用它,
         * 并在需要时使用提供的ThreadFactory创建新线程。
         *
         * @param threadFactory 创建新线程使用的factory
         * @return 新创建的线程池
         * @throws NullPointerException 如果threadFactory为空
         */
        public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
            return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), threadFactory);
        }
    
    • CachedThreadPool的corePoolSize被设置为空(0),maximumPoolSize被设置为Integer.MAX.VALUE,即它是无界的,这也就意味着如果主线程提交任务的速度高于maximumPool中线程处理任务的速度时,CachedThreadPool会不断创建新的线程。极端情况下,这样会导致耗尽cpu和内存资源。
    • CachedThreadPool的execute()方法的执行示意图
      alt
    • 图片说明:

    • 1.首先执行SynchronousQueue.offer(Runnable task)。如果当前maximumPool中有闲线程正在执行SynchronousQueue.poll(keepAliveTime,TimeUnit.NANOSECONDS),那么主线程执行offer操作与空闲线程执行的poll操作配对成功,主线程把任务交给空闲线程执行,execute()方法执行完成,否则执行下面的步骤2;
    • 2.当初始maximumPool为空,或者maximumPool中没有空闲线程时,将没有线程执行SynchronousQueue.poll(keepAliveTime,TimeUnit.NANOSECONDS)。这种情况下,步骤1将失败,此时CachedThreadPool会创建新线程执行任务,execute方法执行完成;
    • 7.ScheduledThreadPoolExecutor详解
    public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
            return new ScheduledThreadPoolExecutor(corePoolSize);
        }
    
    • 执行逻辑:
      alt

    • 1.首先将 Runnable/Callable 封装为 ScheduledFutureTask,延迟时间作为比较属性;

    • 2.然后加入 **DelayedWorkQueue **队列中,每次取出队首延迟最小的任务,超时等待,然后执行;

    • 3.最后判断是否为周期任务,然后将其重新加入 **DelayedWorkQueue **队列中;

    • scheduleAtFixedRate和scheduleWithFixedDelay讲解:

    ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
            scheduledExecutorService.scheduleAtFixedRate(() -> {
                try {
                    sleep(1000);
                    System.out.println("run task" + new Date().toLocaleString());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }, 3, 5, TimeUnit.SECONDS);
            scheduledExecutorService.scheduleWithFixedDelay(() -> {
                try {
                    sleep(1000);
                    System.out.println("run task" + new Date().toLocaleString());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }, 3, 5, TimeUnit.SECONDS);
    
    • scheduleAtFixedRate,固定频率周期任务,注意一次任务超时,会持续的影响后续的任务周期;

    • scheduleWithFixedDelay,固定延迟周期任务,即每次任务结束后,超时等待固定时间;

    • ScheduledThreadPoolExecutor 线程最多为核心线程,最大线程数不起作用,因为 DelayedWorkQueue 是无界队列;

    • 各种线程池的适用场景介绍

    • FixedThreadPool: 适用于为了满足资源管理需求,而需要限制当前线程数量的应用场景。它适用于负载比较重的服务器;

    • SingleThreadExecutor: 适用于需要保证顺序地执行各个任务并且在任意时间点,不会有多个线程是活动的应用场景。

    • CachedThreadPool: 适用于执行很多的短期异步任务的小程序,或者是负载较轻的服务器;

    • ScheduledThreadPoolExecutor: 适用于需要多个后台执行周期任务,同时为了满足资源管理需求而需要限制后台线程的数量的应用场景,

    • SingleThreadScheduledExecutor: 适用于需要单个后台线程执行周期任务,同时保证顺序地执行各个任务的应用场景。

    展开全文
  • QGraphicsView 框架学习() 设计问题 书到用时方恨少啊,遇到一设计问题,为了给QGraphicsItem添加一些特性,比如给它们添加一选择框,提供resize操作,前面用的方法是子类化这类,现在发现这方法挺麻烦的...

    QGraphicsView 框架学习(六) 设计问题

    书到用时方恨少啊,遇到一个设计问题,为了给QGraphicsItem添加一些特性,比如给它们添加一个选择框,提供resize操作,前面用的方法是子类化这个类,现在发现这个方法挺麻烦的。赶快翻书,《设计模式》给出了Adapter等结构模式,《设计模式新思维》给出了模板实现设计模式的方法,目前的问题是尽量利用Qt提供的现成的类,尽量复用现有的工具,那么就 Adapter+template吧。可是问题又来啦,我们需要动多态啊,item需要动态绑定啊,没找到template动态绑定的方法,只能自己做实验了。
    定义一个模板基类,模板参数传递一个QGraphicsItem类型。我们可以实现不同的子类来完成QGraphicsItem的resize操作,而不用对QGraphicsItem类型做修改。这个类,提供了两个方法,resize用来改变图形大小。另外一个给图形添加文本。

    template < typename T >
    class AbstractControl
    {
    public:
    AbstractControl( T * shape )
        :m_shape(shape)
    {}
        virtual void reszie( int handle , const QPointF & point ){
        qDebug()<<"AbstractControl:"<< m_shape->boundingRect();
    }
    virtual void setText( const QString& text ) {}
    protected:
    ~AbstractControl(){}
    T * m_shape;
    };
    // 适配QGraphicsSimpleTextItem对象
    template < typename T >
    class NullControl : public AbstractControl<T>
    {
    public:
    NullControl( T * shape )
        :AbstractControl<T>(shape)
    {}
    void reszie( int handle , const QPointF & point ){
    
        qDebug()<<"NullControl:"<< AbstractControl<T>::m_shape->boundingRect();
    }
    void setText(const QString& text )
    {
        AbstractControl<T>::m_shape->setText(text);
    }
    };
    
    //矩形对象
    template < typename T >
    class RectControl : public AbstractControl<T>
    {
    public:
    RectControl( T * shape )
        :AbstractControl<T>(shape)
    {}
    void reszie( int handle , const QPointF & point ){
        AbstractControl<T>::m_shape->setRect(-50,-50,100,100);
        qDebug()<<"RectControl:"<< AbstractControl<T>::m_shape->boundingRect();
    }
    };
    
    //椭圆对象
    template < typename T >
    class EllipseControl : public AbstractControl<T>
    {
    public:
    EllipseControl( T * shape )
        :AbstractControl<T>(shape)
    {}
    void reszie( int handle , const QPointF & point ){
        AbstractControl<T>::m_shape->setRect(-50,-50,100,100);
        AbstractControl<T>::m_shape->setStartAngle(30*16);
        AbstractControl<T>::m_shape->setSpanAngle(120*16);
        qDebug()<<"EllipseControl:"<< AbstractControl<T>::m_shape->boundingRect();
    }
    };
    
    //定义一个图元,多重继承 AbstractControl和QGraphicsItem类,我们可以在这里继续给它添加一些通用功能。
    
    template < class BaseType , template<class> class Control >
    class RCShape : public Control < BaseType >
               ,public BaseType
    {
    public:
    RCShape(QGraphicsItem * parent = 0 )
        : Control< BaseType >( this ),BaseType(parent)
    {
        BaseType::setFlag(QGraphicsItem::ItemIsMovable, true);
        BaseType::setFlag(QGraphicsItem::ItemIsSelectable, true);
        BaseType::setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
        this->setAcceptHoverEvents(true);
    }
    };
    
    //template的动态多态,不知道真正的template是怎么实现动多态的,反正我就是这么实现的。
    
    

    //声明了一个基本类型做我接口类,模板参数选择的是 QGraphicsItem,和AbstractControl类,它们同样都是基本的接口类型。

        typedef RCShape<QGraphicsItem,AbstractControl> AbstractShape;
    
    //动态绑定
    //相当于
    // class RCShape : public EllipseControl , public QGraphicsEllipseItem;
    AbstractShape *item = qgraphicsitem_cast<AbstractShape*> (new   RCShape<QGraphicsEllipseItem , EllipseControl >);
    item->reszie(0,QPointF());
    item->setPos(scene->sceneRect().center());
    scene->addItem(item);
    
    //动态绑定
    //相当于
    //class RCShape : public RectControl , public QGraphicsRectItem;
    AbstractShape *item1 = qgraphicsitem_cast<AbstractShape*> (new  RCShape<QGraphicsRectItem , RectControl > );
    item1->reszie(0,QPointF());
    item1->setPos(300,300);
    scene->addItem(item1);
    
    //动态绑定
    //相当于
    //class RCShape : public NullControl , public QGraphicsSimpleTextItem;
    AbstractShape *item2 = qgraphicsitem_cast<AbstractShape*> (new   RCShape<QGraphicsSimpleTextItem , NullControl > );
    item2->reszie(0,QPointF());
    item2->setText(tr("Demo C++ Template Dynamic Polymorphism"));
    item2->setPos(300,200);
    scene->addItem(item2);
    
    

    总结,mixin模式模板类作为接口类,实现动多态也是可以的,但是需要对多重继承的父类定义抽象接口,声明一个完全都是基本类型的模板类做接口对象的类型。然后通过dynamic_cast实现动态绑定。

    展开全文
  • 在这篇文章中,我将介绍六个思维技巧来帮助你更快地学习JavaScript,并成为一个更快乐、更富有成效的程序员。 1.不要让未来的决策阻止你现在前进的方向 很多人学习JavaScript,问的第一个问题往往是“我应该使用哪个...
  • 设计思维

    2019-02-04 05:27:57
    什么是设计思维:设计一解决方案------一可以被重复使用的解决问题的方法框架或一系列步骤 提供解决问题的原型和一系列工具 第二部分 体系(大过程): 需求理解 问题定义 思维发散 原型设计 模型迭代 ...

    设计思维基本知识

    第一部分
    由来:以人为本-------满足用户真实需求关注用户需求的本质
    什么是设计思维:设计一个解决方案------一个可以被重复使用的解决问题的方法框架或一系列步骤 提供解决问题的原型和一系列工具
    第二部分
    体系(六大过程)
    需求理解
    问题定义
    思维发散
    原型设计
    模型迭代
    成果发布
    需求理解
    1
    (2).什么是需求理解
    行为与心理感知联系
    (1).需求理解的重要性
    用户的表面行为与潜在需求 往往并不完全一致。理解,不仅仅是理解用户的行为, 更需要理解用户的真实需求。 满足用户的最深层需要,让设计有根据, 弥补了设计师对目标用户了解的不足。
    2 如何理解用户需求
    (1)理解中的移情
    将心比心,感同身受将对方的情绪、行为、想法,转移到自己身上, 使自己拥有与对方相同的体验.
    在这里插入图片描述

    (2)理解中的同理体验
    例子
    同理心 :我能明白 你的难过
    同情心:抱歉勾起 你的难过
    (3).理解的步骤和方法
    在这里插入图片描述问题定义
    1 为什么进行问题定义
    找到真正重要的问题。在充分理解需求的基础上, 详细地定义正在试图解决的问题, 以获得更精确的核心设计问题。通俗的说:就是要确定用户痛点,明确用户需求。
    正确界定问题 ----找到最佳着眼点,省力高效地完成任务。
    2 用户问题定义的步骤
    Step 1. 总结需求
    在需求理解的基础上,总结需求内容。
    Step 2. 配合工具分析需求
    确定我们的目标:我们在为谁而设计?他们需要做什么? -被设计者在想什么?被设计者看到了什么?被设计者听到了什么?被设计者如何谈论这件事? - 通过以上的行为观察,我们能得出他的痛点是什么? - 被设计者会因为什么而开心?
    Step 3. 定义观点
    根据移情图的结果,重新定义目标用户,找到用户痛点,并且确定产品愿景,形成一个新的观点,对设计方向进行规划和约束。
    Step 4. 问题阐述
    在上两步的结果上,根据问题阐述的三要素定义问题,追求问题的全面性、完整性、可行性,同时进行适当的调整完善。
    问题定义的目的-----问题定义: 找到真正需要解决的问题
    寻求问题的解决方案。
    思维发散
    1.为何进行思维发散
    思维发散的定义:运用开放性思维 提出更多方案,创造更多选择,寻找最优解。
    在这里插入图片描述
    2 如何进行思维发散
    实践步骤
    在这里插入图片描述思维发散的目的------思维发散:创造更多的最优解

    原型设计
    1 原型设计及其重要性
    (1).什么是原型设计?
    赋予想法具体的外观,利用模型进行设计构思。
    (2).原型设计的重要性
    有效地避免重要元素被忽略,阻止作出不准确不合理的假设 。
    a.降低成本 - 在原型设计阶段能够弥补大部分的错误,而这些 错误在开发阶段再进行处理成本是很高的。
    b.便于沟通 - 原型比文字更加直观有效,使设计师更轻松更快 速地与开发人员、需求方进行沟通,也更容易接受来自外界 的反馈。
    用原型设计论证设计的可行性(长处与不足),寻找更好的设计机.
    2 如何进行原型设计
    实践步骤
    在这里插入图片描述原型设计的目的
    制作模型:快速实现推进设计方案
    迭代:在迭代中不断优化方案
    模型迭代
    1.什么是模型迭代?
    根据测试及反馈的结果,不断更新完善原型
    2 如何进行模型迭代
    模型迭代的三个过程
    始终贯穿测试-反馈-迭代的循环, 其中测试是迭代过程的关键。
    测试的步骤如下:
    在这里插入图片描述模型迭代的目的-----模型迭代:做出最佳的模型。
    成果发布

    整理自浙江大学张克俊老师的慕课资料。

    展开全文
  • 总述1. 鲁百年老师分享的设计思维的三个步骤与六个流程2. 《图书馆中的设计思维-以用户为中心的设计工具包》3. 《设计思维-为教育工作者准备的工具包》二.思考三.结语参考资料 一.总述 对于设计思维的步骤流程,...
  • 当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"。 输出描述: 如果当前字符流没有存在出现一次的字符,返回#字符。 题目给出的代码框架: class Solution { public: //Insert one char ...
  • 认知1 认知1.1 时间黑洞1.1.1 产生的原因1.1.2 时间的特性1.2 人生目标1.2.1 人生规划的六个高度1.2.2 人生富足的动态平衡1.3 效率和平衡1.3.1 做正确的事1.3.2 把事情做正确 (详细内容见“方法和工具”)方法和工具2...
  • 本课程总体分上、下两部,上部解决应用PureMVC框架开发项目问题,下部则着力解决深入掌握框架源码核心、彻底掌握框架思想、建立框架思维,为开发自己的专属框架(以及成为游戏架构师)打下坚实基础! 本课程下部...
  • 思维导图参考:【十四】Java IO框架章节思维导图 【习题与详解】 1、利用IO输入、输出流来复制图片,你试过吗? 2、(File类、递归)Java写一查找盘符内指定文件的代码,你可以试试! 3、IO流小练习 一、流的...
  • 读书笔记之《梁宁增长思维30讲》 梁宁增长思维30讲 发刊词 | 增长能力,就是持续作出正确决定的能力 ..............六个模块 第一, 一张全景作战地图。 第二,四个增长关卡。 机会拿捏、模式取巧、组织扩容、战略
  • (事先用Word写好的,再贴上来,格式有点...,有时间再调整,如果看不清楚,请...但是从用的角度来讲,很多人已经认为比较“复杂”了,但是我认为这思维方式有关,当人看到一电视机,然后看完说明书(相当于 S...
  • (二)团队协作(三)开源框架(四)架构师筑基(五)高性能架构()B2C商城项目实战(七)并发编程(八)设计模式有了路线解析图,有没有免费资料?有没有志同道合的小伙伴共同进步?以上技术方向我们有自己的...
  • ——梁宁时隔自己零基础入门开始学习产品已经六个月了,所以最近重读梁宁老师的产品思维三十讲,记录了一些所得和所想,这个专栏不定期更新读书笔记。如果有任何问题也欢迎多多讨论和交流~读书笔记01-05 为第一模块...
  • 项思考帽

    2009-02-03 11:49:45
    一、项思考帽的来源: “爱德华·德·波诺博士是一位拥有医生、心理学家及社会学家专业的教授,...它的主要功能在于为人们建立一思考框架,在这个框架下按照特定的程序进行思考,从而极大地提高企业与个人的效能...
  • 注册会计师备考是要掌握住核心点的,对于CPA科来说,核心知识点的精华就是思维导图(框架图)!无论是纵览全教材,还是理清楚各个重点之间的知识点逻辑及内在关系,都大有裨益!CPA科当中,《会计》作为报名人数...
  • 顶思考帽是英国学者爱德华·德博诺(Edward de Bono)博士开发的一种思维训练模式,或者说是一全面思考问题的...顶思考帽是管理思维的工具,沟通的操作框架,提高团队IQ的有效方法。 怎么用? 以下,Enjoy: .
  • 概述:第一张是总图,如果大家觉得看起来不方便,可以看底下的分支结构图,每章节都有! 基础知识体系总图 一、Java核心语法 二、面向对象 三、 常用API 四、集合框架 五、I/O 、多线程 七、异常 八、...
  • 它的主要功能在于为人们建立一思考框架,在这个框架下按照特定的程序进行思考,从而极大地提高企业与个人的效能,降低会议成本、提高创造力、解决深层次的沟通问题。它为许多国家、企业与个人提供了强有力的管理...
  • ●用NLP解决问题,达成目标的“获致成果公式”《激发心灵的潜力》提到一条...同时,它也是一个思维工具,让我们解决问题里有步骤。解决问题要用NLP的获致成果公式。目的,策略,资源,执行。NLP重视的是效果,而不是...
  • API文档,电子书,各种思维导图资源,百度网盘资源应有尽有一、面试题、简历资源二、各类思维导图三、大数据学习四、Linux五、各类常用开发工具类、百度网盘各类资源,包含java开发,项目实战,MYSQL,框架学习,...
  • 首先仔细读题,初步在脑中完成一个思维导图。 然后将其写下来: 不用非常清楚,能想到什么问题就写上去,把问题整体模块化,复杂简单化。 二、代码部分 1.先写出方法头,构建一个具体框架 代码如下(示例): 这样...
  • 脚本的学习一直不得章法,之前都是囫囵吞枣式的学习,现在决定好好梳理下思路,看看究竟哪里是弱项。...对于一程序的开发来说,一定是先从整体逻辑框架再到具体细节处理。接下来我从一脚本中去...

空空如也

空空如也

1 2 3 4 5 ... 7
收藏数 122
精华内容 48
关键字:

六个思维框架