精华内容
下载资源
问答
  • 1.总体来说设计模式分为三大类: 创建型模式,共五:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。 结构型模式,共七:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享...

    1.总体来说设计模式分为三大类:

    创建型模式,共五种:工厂方法模式抽象工厂模式单例模式建造者模式原型模式

    结构型模式,共七种:适配器模式装饰者模式代理模式外观模式桥接模式组合模式享元模式

    行为型模式,共十一种:策略模式模板方法模式观察者模式迭代子模式责任链模式命令模式备忘录模式状态模式访问者模式中介者模式解释器模式

    这里写图片描述

    2.设计模式的六大原则

    1、开闭原则(Open Close Principle)

    开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。

    2、里氏代换原则(Liskov Substitution Principle)

    里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。—— From Baidu 百科

    3、依赖倒转原则(Dependence Inversion Principle)

    这个是开闭原则的基础,具体内容:真对接口编程,依赖于抽象而不依赖于具体。

    4、接口隔离原则(Interface Segregation Principle)

    这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。还是一个降低类之间的耦合度的意思,从这儿我们看出,其实设计模式就是一个软件的设计思想,从大型软件架构出发,为了升级和维护方便。所以上文中多次出现:降低依赖,降低耦合。

    5、迪米特法则(最少知道原则)(Demeter Principle)

    为什么叫最少知道原则,就是说:一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。

    6、合成复用原则(Composite Reuse Principle)

    原则是尽量使用合成/聚合的方式,而不是使用继承。

    展开全文
  • 这些Shader被分为五个大类: Normal,Transparent,Transparent Cutout,Self-llluminated,Reflective。 在这里简单的介绍一下Nomral Shader的相关使用。 (一) Normal Shader Family  这个家族一共9个...

    Unity3D自带的60多个Shader。 这些Shader被分为五个大类:

    Normal,Transparent,Transparent Cutout,Self-llluminated,Reflective。

    在这里简单的介绍一下Nomral Shader的相关使用。

    (一) Normal Shader Family

          这个家族一共9个Shader,都是针对不透明的对象的。

     

    (1) Vertex-Lit:

          最简单的一种Shader之一,所有照射在该物体上的光在一个Pass里面渲染完,光源只在顶点计算。所以不会有任何基于像素渲染得效果,比如说:normal mapping,light cookies和shadows.这个shader对模型的剖分(将一个物体从几何描述变为多边形表示的过程)非常敏感,如果你将一个点光源放在很靠近一个立方体的一个顶点那里,并且对立方体使用这个shader,光源只会在角落计算。基于像素光照的shader对剖分没有要求,在表现圆形高光上效果也很好。如果上述情况时你想要的效果,你可以考虑使用一个基于像素光照的shader或者增加模型的剖分。(增加顶点数)

          总的来说,这个shader的渲染代价比较小。这个shader包含了2个subshader,分别对应可编成管线和固定管线。是所有硬件都支持的一个最基本的shader。如果设备支持可编成管线,那使用可编成管线的subshader,否则使用固定管线的。

          Unity3D Shader/Normal/Vertex-Lit

     

    (2) Diffuse:

          Diffuse基于一个简单的光照模型-Lambertian,光照强度随着物体表面和光入射角夹角的减小而减小(即光垂直于表面时强度最大)。光照的强度只和该角度有关系,和摄像机无关。由于这是一个基于像素光照的shader,因此他有这类shader的优势,同时他需要设备支持可编程管线,如果设备不支持,则自动使用Vertex-Lit这个Shader。

          总的来说,这个shader渲染代价比较小。

     

           Unity3D Shader/Normal/Diffuse

     

    (3) Specular

          Specular 使用和Diffuse相同的光照模型,但是添加了一个和观察角度相关的反射高光。这个被称为Blinn-Phong光照模型。他包含了一个反射强光,这个反射高光物体表面角度,光的入射角度以及观察者角度都有关系。这种高光计算方法实际上是对实时光源模糊反射的一种具有可行性的模拟。模糊的等级通过inspector里面Shininess这个变量控制。

          主纹理的alpha通道被用来当作Specular Map来使用(有时候也称gloss map),它定义了物体的反光率。纹理中alpha里面全黑 的部分将完全不反光(即反光率为0%)。而全白的的部分反光率为100%。这个Map在你的物体在不同的部分有不同的反光率的时候非常有用。比如说,锈迹斑斑的金属会反光率低,而磨光的金属反光率比较高。口红的反光率比皮肤高,而皮肤的反光率比棉质衣服高。一个精心制作的Specular Map将会让玩家身临其境。如果目标设备不支持可编程管线,则自动使用Vertex-Lit这个Shader。

           这个shader的渲染代价会比较大。

     

           Unity3D Shader/Normal/Specular

     

     (4)Bumped Diffuse

           同Diffuse Shader一样,这个Shader基于Lambertian光照模型,同时使用了normal mapping技术来增加物体表面细节。相对于通过增加剖分来表现物体表面细节的方式,normal mapping并不改变物体的形状,而是使用一张称为Normal Map的特殊纹理来达到这种效果。在normal map中,每个象素的颜色代表了该像素所在物体表面的法线,然后通过这个法线(而不是通过物体模型计算而来的法线)来计算光照。可以说Normal Map在计算光照的过程中“高效地修改”了整个模型。

           如何创建Normal maps:你可以通过导入一张普通的灰度图(白色表示凸起,黑色表示凹进)Unity会自动将它转换为Normal Map。

           技术细节:这里使用Normal map是一种“Tangent space Normal Map”,Tangent space(正切空间)是一个跟随模型物体表面的空间。在这个空间中,z轴始终从表面指向外面。Tangent space Normal Map相对于另一种被称为“Object space Normal Map”来说有点复杂,但是他有一些优势。1)可以使用在各种奇形怪状的表面  2)便于在同一物体不同区域或者不同物体间复用

            具体关于Tangent Space Normal Map和Object Space Normal Map的区别,下次再讲。

            如果调用这个shader失败,则会调用Diffuse这个shader,一般而言,该shader渲染代价低。

     

             Unity3D Shader/Normal/Bumped Diffuse

     

     (5) Bumped Specular

            和Specular一样的光照模型,相比Specular而言,它使用一张Tangent Space Normal Map来描述物体表面法向量的变化,来增加物体细节。(关于normal map具体见Bumpped Diffuse)如果调用失败,则使用Specular这个shader,一般而言,这个shader的渲染代价会比较大。

            Unity3D Shader/Normal/Bumped Specular

     

    (6) Parallax Diffuse

            Parallax Normal mapped与传统的normal mapped一样,但是对“深度”的模拟更佳。额外的深度效果是通过Height Map(高度图)来实现的。Height Map在Normal map的alpha通道里面保存。全黑表示么有高度,而白色表示有高度。通常这用来表现石头或者砖块间的裂缝。

            Parallax mapping的技术很简单,因此会有些人工痕迹或者不太正常的效果出现。尤其是,急剧陡峭的高低转换在高度图里面应该避免。在inspector里面调整height数值来调整高度的范围,有时候会造成物体不真实,凌乱的情况。因此建议使用高度变化平缓的高度图或者将高度数值设置比较低,让表面看起来比较平缓。

            这个shader的渲染代价相比bumped diffuse而言更大。如果调用这个Shader失败,则自动使用Bumped Diffuse。

            Unity3D Shader/Normal/Parallax Diffuse

     

     

    (7) Parallax Specular

            与Bumped Spcular相比,增加了一张Height Map来描述深度细节。关于Height Map,见parallax Diffuse。如果调用失败,则调用Bumped Specular这个Shader。

     

             Unity3D Shader/Normal/Parallax Specular

     

     

    (8) Decal

            这个Shader在unity文档里面的描述和Unity3.0有明显的实现区别,文档由于比较老,07年写的,官网下的Built-in Shader里面,decal是使用可编程管线实现的,就是说,如果你的机器不支持可编程管线,会使用diffuse,因为diffuse也不需要可编程管线,所以只能使用vertex-lit。这个Shader除了主纹理之外,这个Shader还是用了第二张纹理用来描述细节。第二张用来Decal(贴花)的纹理使用alpha通道来确定是否覆盖主纹理。贴花用的纹理只是对主纹理的补充。比如说你有一个砖砌的墙壁,你可以使用一个砖块的纹理作为主纹理,然后使用带有alpha通道的Decal纹理在墙壁的不同地方涂鸦。

           Unity3D Shader/Normal/Decal

     

     

    (9) Diffuse Detail

            这是一个普通的diffuse shader加上一些额外数据的shader。它允许你定义第二张纹理,称为Detail Texture。当camera靠近的时候,Detail Texture逐渐显示出来,一般用于地形。比如说,当你使用一张低分辨率的纹理拉升到整个地形上的时候。随着camera逐渐拉近,低分辨率的纹理开始模糊,这不是我们想要的效果。为了避免这个效果,创建一张Detail 纹理会将地形tile化。在这种模式下,随着camera逐渐拉近,额外的细节将会出现以避免出现模糊的效果。

            Detail 纹理是覆盖在主纹理上面的。Detail纹理中深色的部分将会使得主纹理变深,而淡色的部分将会使主纹理变亮,Detail纹理通常是浅灰色。(与Decal里面Decal纹理不同的是,Decal纹理是RGBA,通过alpha控制Decal Texture与Main Texture的融合,而Detail的纹理是RGB,直接是两张纹理的rgb通道分别相乘再*2,就是说,Detail纹理中颜色数值 = 0.5不会改变主纹理颜色,>0.5会变亮,<0.5加深)

            Unity3D Shader/Normal/Diffuse Detail

    展开全文
  • 三大系列: offset系列 scroll系列 client系列 offset系列 offsetParent 定位父级 在理解偏移位置大小之前,我们先来看看常常被忽略的 offsetParent 定位父级 ...主要分为以下几种情况 : 元素自身没有 ...

    三大系列:

    offset系列

    scroll系列

    client系列



    offset系列


    offsetParent 定位父级

    在理解偏移位置大小之前,我们先来看看常常被忽略的 offsetParent 定位父级

    offsetParent 定义是 : 获取当前元素最近的经过定位(position不等于static)的父级元素(元素自身为参照的父级元素)。主要分为以下几种情况 :

    1. 元素自身没有 fixed 定位,且父级也没有定位,返回 body

      <div id="content">
          <div id="box">
               <div id="test">测试</div>
          </div>
      </div>
      <script>
          var test = document.getElementById("test");
          var content = document.getElementById("content");
          console.log(test.offsetParent);		// body
      </script>
      

            在这里插入图片描述

    1. 元素自身没有 fixed 定位,且父级元素都存在定位的情况 (不包括position: static),offsetParent 返回 离自身元素最近的经过定位的父级元素。

      <div id="content" style="position: relative;">
          <div id="box" style="position: absolute;">
              <div id="test">测试</div>
          </div>
      </div>
      <script>
          var test = document.getElementById("test");
          var content = document.getElementById("content");
          console.log(test.offsetParent);     // box
      </script>
      

            在这里插入图片描述

    1. 当元素自身有 fixed 固定定位,我们知道固定定位的元素相对于视口定位,offsetParent 返回 null

      <div id="content">
          <div id="box">
              <div id="test" style="position: fixed;">测试</div>
          </div>
      </div>
      <script>
          var test = document.getElementById("test");
          var content = document.getElementById("content");
          console.log(test.offsetParent);     // null
      </script>
      

                    

    【注意点:】 火狐浏览器存在兼容问题,如下:

    <div id="content">
        <div id="box">
            <div id="test" style="position: fixed;">测试</div>
        </div>
    </div>
    <script>
        var test = document.getElementById("test");
        var content = document.getElementById("content");
    	// 火狐浏览器没有考虑固定定位相对于视口而言,返回body,其它浏览器都返回null
        console.log(test.offsetParent);     // body
    </script>
    

    在这里插入图片描述

    1. 【注意点:】 body的 offsetParent 返回结果为 null
    <script>
        console.log(document.body.offsetParent);    //谷歌 火狐 IE 为null
    </script>
    


    offsetWidth 和 offsetHeight

    offsetWidth : 用来获取对象自身的的宽度

    offsetWidth = width + border + padding; 
    

    offsetHeight : 用来获取对象自身的的高度

    offsetHeight = height + border + padding
    
    <div id="content">
        <div id="box" style="width: 200px;height: 200px;background-color: gold;">
            <div id="test" style="width: 100px;height: 100px;border: 5px solid red; padding: 20px; margin: 10px; background-color: #008c8c;">测试</div>
        </div>
    </div>
    <script>
        var content = document.getElementById("content");
        var test = document.getElementById("test");
        // 数字型:150 = width :100 + border-left-width:5 + border-right-width :5 + padding-left:20px +  padding-right:20px
        console.log(test.offsetWidth);   
        // 数字型:150 = width :100 + border-top-width:5 + border-bottom-width :5 + padding-top:20px +  padding-bottom:20px
        console.log(test.offsetHeight);
    </script>
    

    在这里插入图片描述

    offsetwidth 与 style.width 的区别

    1. 得到的结果值不同
    • offsetwidth :获取元素的真实高度
    • style.width :只能获取行内样式style="width :100px;",如果样式写到了其他地方(如style代码块,外部css样式),甚至根本就没写,便无法获取
    1. 获得的值的类型不同:
    • offsetwidth :数值类型
    • style.width :带单位的字符串
    1. 使用方式的不同
    • offsetwidth :只读属性, 只能获取属性值, 不能设置元素的高度
    • style.width :能获取、设置行内的width 属性值


    offsetLeft 和 offsetTop


    offsetLeft :

    ​   offsetLeft表示元素的左外边框至offsetParent元素的左内边框之间的像素距离

    offsetTop :

    ​ offsetTop表示元素的上外边框至offsetParent元素的上内边框之间的像素距离

    在这里插入图片描述

    实例

    标准流下父级盒子无定位

    <div id="content">
        <div id="box" style="width: 200px;height: 200px;background-color: gold;">
            <div id="test" style="width: 100px;height: 100px;border: 5px solid red; padding: 20px; margin: 30px; background-color: #008c8c;">测试</div>
        </div>
    </div>
    <script>
        var content = document.getElementById("content");
        var test = document.getElementById("test");
        // 父级无定位相对body:38  = test.marginLeft(30) + body(8)
        console.log(test.offsetLeft);
        // 父级无定位相对于body: 30 = test.marginTop(30)-->标准流下外边距发生合并所以是30
        console.log(test.offsetTop);
    </script>
    

    在这里插入图片描述


    脱标下父级盒子有定位(不含position:static)

    <div id="content">
        <div id="box" style="width: 200px;height: 200px;background-color: gold; position:absolute;">
            <div id="test" style="width: 100px;height: 100px;border: 5px solid red; padding: 20px; margin: 30px; background-color: #008c8c;">测试</div>
        </div>
    </div>
    <script>
        var content = document.getElementById("content");
        var test = document.getElementById("test");
        // 父级有定位相对父级box:30  = test.marginLeft(30)
        console.log(test.offsetLeft);
        // 父级有定位相对于父级box: 30 = test.marginTop(30)
        console.log(test.offsetTop);
    </script>
    

    在这里插入图片描述


    scroll系列

    1. scroll 指滚动,包括这个元素没显示出来的实际宽度,包括padding,不包括滚动条、border
    2. scrollHeight : 获取对象的滚动高度,对象的实际高度;
    3. scrollWidth : 获取对象的滚动宽度;
    4. scrollTop : 当元素自身的onscroll事件发生时,元素向上卷曲出去的距离
    5. scrollLeft:当元素自身的onscroll事件发生时,元素向左卷曲出去的距离
     <div id="box" style="width: 200px;height: 300px; overflow: auto;border: 2px solid #008c8c;">
     		// 乱数假文(测试)
            Lorem ipsum dolor sit amet, consectetur adipisicing elit. Impedit, quibusdam sapiente iusto omnis vitae ab rerum provident adipisci in cum. Corrupti, tenetur aliquam libero molestias in nisi facere aperiam perferendis!
            Consectetur dolor ab aperiam consequuntur dolore, quasi, reprehenderit nulla accusantium in pariatur deleniti. Obcaecati temporibus quos consequuntur explicabo totam, magni adipisci mollitia earum numquam, ab iste quia sequi modi dolorem.
            Unde iure suscipit nihil ipsum labore sequi. Ducimus saepe, autem et eaque, vitae voluptatum alias eligendi officiis iste quia placeat illum tenetur labore blanditiis. Tempora fugit totam explicabo enim cum?
            Soluta optio, atque aliquam, magnam minima eligendi vero a eveniet sint recusandae sequi magni, praesentium quidem. Itaque obcaecati aliquam sint. Non consequatur sunt aliquam, unde natus quasi quaerat obcaecati quo?
            Veniam iusto adipisci, ipsum sed impedit qui eum, iste neque ex incidunt minima dolorem ipsam molestiae. Temporibus commodi atque sed ipsam magnam, neque quod delectus unde. Dolores nobis neque sit?
    </div>
    <script>
       var box = document.getElementById("box");
        // 1144 内容的实际高度
        console.log(box.scrollHeight);
        // 183 box的宽度 - 滚动条占用的宽度
        console.log(box.scrollWidth);
        // 0 页面滚动被卷去的高度
        console.log(box.scrollTop);
        // 0 页面横向拉动被卷去的宽度
        console.log(box.scrollLeft);
    </script>
    

    在这里插入图片描述

    //测试 scrollTop 随着滚动被卷去的高度
    <script>
        var box = document.getElementById("box");
        // 测试scrollTop
        box.onscroll = function() {
            console.log(this.scrollTop);
        }
    </script>
    

    在这里插入图片描述

    案例 : 用户协议,浏览完后才可确认

    <div id="box" style="width: 200px;height: 300px; overflow: auto;border: 2px solid #008c8c;">
        Lorem ipsum dolor sit amet, consectetur adipisicing elit. Impedit, quibusdam sapiente iusto omnis vitae ab rerum provident adipisci in cum. Corrupti, tenetur aliquam libero molestias in nisi facere aperiam perferendis!
        Consectetur dolor ab aperiam consequuntur dolore, quasi, reprehenderit nulla accusantium in pariatur deleniti. Obcaecati temporibus quos consequuntur explicabo totam, magni adipisci mollitia earum numquam, ab iste quia sequi modi dolorem.
        Unde iure suscipit nihil ipsum labore sequi. Ducimus saepe, autem et eaque, vitae voluptatum alias eligendi officiis iste quia placeat illum tenetur labore blanditiis. Tempora fugit totam explicabo enim cum?
        Soluta optio, atque aliquam, magnam minima eligendi vero a eveniet sint recusandae sequi magni, praesentium quidem. Itaque obcaecati aliquam sint. Non consequatur sunt aliquam, unde natus quasi quaerat obcaecati quo?
        Veniam iusto adipisci, ipsum sed impedit qui eum, iste neque ex incidunt minima dolorem ipsam molestiae. Temporibus commodi atque sed ipsam magnam, neque quod delectus unde. Dolores nobis neque sit?
    </div>
    <input type="button" value="确认" disabled>
    <script>
        var box = document.getElementById("box");
        var ipt = document.querySelector("input");
        // 用户协议,浏览完后才可确认====> 盒子的高度(offsetHeight获取) 》= (内容的高度 - 用户浏览卷去的高度)
        var scrollH = box.scrollHeight;
        var offsetH = box.offsetHeight;
        box.onscroll = function() {
            offsetH >= scrollH - this.scrollTop ? ipt.disabled = false : ipt.disabled = true;
        }
        ipt.onclick = function() {
            alert("您好哇");
        }
    </script>
    

    在这里插入图片描述

    scrollTop 和 scrollLeft的兼容

    /**
     * @获取页面被卷去的高度和宽度 
     * @return: Object
     */
    function getScroll() {
        return {
            top : window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0,
            left : window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft || 0
        }
    }
    

    client系列

    1. client 指元素本身的可视内容,不包括overflow被折叠起来的部分,不包含滚动条、border、包含padding

    2. clientWidth 元素可视区域的宽度 ,边框内部的宽度,不带边框

    3. clientHeight 元素可视区域的高度 ,边框内部的高度,不带边框

    4. clientLeft 元素左边边框的宽度(如果左边有滚动条会包含滚动条的宽度)

    5. clientTop 元素顶部边框的高度 (如果顶部有滚动条会包含滚动条的高度)

    展开全文
  • 工厂模式一般被分为以下几种: 简单工厂模式 工厂方法模式 抽象工厂模式 1.简单工厂模式 简单工厂模式是属于创建型模式,又叫做静态工厂方法(Static Factory Method)模式,但不属于23种GOF设计模式之一。...

    23种设计模式之工厂模式

    工厂模式一般被分为以下几种:

    简单工厂模式

    工厂方法模式

    抽象工厂模式

    1.简单工厂模式

    简单工厂模式是属于创建型模式,又叫做静态工厂方法(Static Factory Method)模式,但不属于23种GOF设计模式之一。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式,可以理解为是不同工厂模式的一个特殊实现。

    简单工厂分为三个组成部分:

    • 产品抽象类,定义功能
    • 具体产品类,功能实现
    • 静态工厂类,生产产品
    1.1 产品抽象类

    产品抽象类是用来定义产品的功能,一般以接口或者抽象类的形式展现

    //接口
    public interface IRun {
    	void run();
    }
    
    //抽象类
    public abstract class AbsRun {
    	public abstract void run();
    }
    
    1.2 具体产品类

    产品类就是产品抽象类的实现,具体功能对象的具体实现。(这里可以进行更加具体的功能分类)

    //两条腿的产品实现
    public class TwoRun implement IRun {
    	@Override
    	public void run() {
    		System.out.println("我两条腿跑。");
    	}
    }
    
    //四条腿产品实现
    public class FourRun implement IRun {
    	@Override
    	public void run() {
    		System.out.println("我四条腿跑。");
    	}
    }
    
    //四条腿以上产品实现
    public class MoreRun implement IRun {
    	@Override
    	public void run() {
    		System.out.println("我有更多腿跑。");
    	}
    }
    
    1.3 静态工厂类

    静态工厂类是用来生产产品的实例的,通过某种定义好的产品类型来创建对应的产品实例。

    //工厂类
    public class RunFactory{
    	public static IRun create(String type){
    		IRun iRun;
    		switch(type){
    			case "2":
    				iRun = new TwoRun();
    				break;
    			case "4":
    				iRun = new FourRun();
    				break;
    			default:
    				iRun = new MoreRun();
    				break;
    	}
    }
    
    public static void main(String[] args){
    	IRun two = RunFactory.create("2");
    	IRun four = RunFactory.create("4");
    	IRun more = RunFactory.create("6");
    	two.run();
    	fout.run();
    	more.run();
    }
    
    打印结果
    -------------------
    我两条腿跑。
    我四条腿跑。
    我更多条腿跑。
    
    
    总结

    这里就是对“run”这个功能的多种实现。在面对这种需求的时候,我们是先写具体的功能类到最后在进行相似功能抽象,向上提取才得到工厂模型的。其实这种思维方式在编程上应该反过来,在写功能之前应该先对功能进行定义,在完善具体产品的实现。这样可以大大减少我们代码Review的时间,还增强了代码拓展性,大大提升了我们开发效率。所以我们利用好设计模式才是程序员进阶必要条件。

    并且在开发过程中我们还可以进行第二层抽象,那就是抽象类,在定义好功能接口之后,我们可以在中间添加抽象类,将公共部分进行合并,产品类只需要进行个性功能的实现,这样产品实现类只体现出不同的功能,也可以简化代码增强可读性。例如:

    public abstract class AbsTwoRun implement IRun {
    	
    	@Override
    	public void run() {
    		packing();
    	}
    	
    	//定义包装方法
    	public abstract void packing();
    	
    }
    
    //具体实现类
    public class ManRun extends AbsTwoRun {
    	@Override
    	public void packing(){
    		System.out.println("我穿着鞋用两只脚跑。");
    	}
    }
    
    public class Checken extends AbsTwoRun {
    	@Override
    	public void packing() {
    		System.out.println("我不穿鞋用两只脚跑。");
    	}
    }
    

    这里就是对功能的拆分,那么工厂方法模型又是怎样呢~

    2 工厂方法模型

    工厂方法模式Factory Method,又称多态性工厂模式。在工厂方法模式中,核心的工厂类不再负责所有的产品的创建,而是将具体创建的工作交给子类去做。该核心类成为一个抽象工厂角色,仅负责给出具体工厂子类必须实现的接口,而不接触哪一个产品类应当被实例化这种细节。

    工厂方法模式是简单工厂模式的衍生,解决了许多简单工厂模式的问题。首先完全实现‘开-闭 原则’,实现了可扩展。其次更复杂的层次结构,可以应用于产品结果复杂的场合。

    我们在介绍简单工厂模型的时候对它进行了拓展。工厂方法模型的具体操作就是将工厂进行了具体功能的分配。

    就上面的例子我们可以将每个类型的产品对应一个工厂实现。

    public interface IFactory {
    	IRun create();
    }
    
    //Two Run
    public class TwoFactory implement IFactory {
    	@Override
    	public IRun create(){
    		return TwoRun();
    	}
    }
    //Four Run
    public class FourFactory implement IFactory {
    	@Override
    	public IRun create(){
    		return FourRun();
    	}
    }
    //More Run
    public class MoreFactory implement IFactory {
    	@Override
    	public IRun create(){
    		return MoreRun();
    	}
    }
    
    

    这样我们就可以直接通过获取产品对应的工厂来获取产品的实例。虽然多了一层封装,但是更便于封装。

    3 抽象工厂模式

    抽象工厂模式是所有形态的工厂模式中最为抽象和最具一般性的一种形态。抽象工厂模式是指当有多个抽象角色时,使用的一种工厂模式。抽象工厂模式可以向客户端提供一个接口,使客户端在不必指定产品的具体的情况下,创建多个产品族中的产品对象。根据里氏替换原则,任何接受父类型的地方,都应当能够接受子类型。因此,实际上系统所需要的,仅仅是类型与这些抽象产品角色相同的一些实例,而不是这些抽象产品的实例。换言之,也就是这些抽象产品的具体子类的实例。工厂类负责创建抽象产品的具体子类的实例。

    • 它由四部分组成:
      1. 抽象工厂:用来定义多个产品的抽象。
      2. 具体工厂:对应具体产品创建产品实例。
      3. 抽象产品:用来定义产品功能。
      4. 具体产品:产品功能实现,通过具体工厂获得。

    抽象工厂

    public interface IFactory {
    	//定义Run产品工厂方法
    	void createRun();
    	
    	//定义包装产品工厂方法
    	void createPacking();
    }
    

    抽象产品

    public interfact IRun {
    	void run();
    }
    
    public interface IPacking() {
    	void packing();
    }
    

    具体产品

    跑的具体产品
    
    //两条腿的产品实现
    public class TwoRun implement IRun {
    	@Override
    	public void run() {
    		System.out.println("我两条腿跑。");
    	}
    }
    
    //四条腿产品实现
    public class FourRun implement IRun {
    	@Override
    	public void run() {
    		System.out.println("我四条腿跑。");
    	}
    }
    
    //四条腿以上产品实现
    public class MoreRun implement IRun {
    	@Override
    	public void run() {
    		System.out.println("我有更多腿跑。");
    	}
    }
    ----------------------------------------
    
    包装的具体实现
    
    //光脚包装产品
    public class NoPacking implement IPacking {
    	@Override
    	public void packing() {
    		System.out.println("我光着脚。");	
    	}
    }
    
    //穿鞋包装产品
    public class Shoes implement IPacking {
    	@Override
    	public void packing() {
    		System.out.println("我穿东西。");
    	}
    }
    
    

    具体工厂

    //野人 产品---两条腿,光着脚
    public class Savage implement IFactory {
    	@Override
    	public IRun createRun() {
    		return new TwoRun();
    	}
    	
    	@Override
    	public IPacking createPacking() {
    		return new NoPacking();
    	}
    }
    打印结果
    ----------
    我两条腿跑。
    我光着脚。
    
    
    //千里马 产品---四条腿,有马掌
    public class Maxima implement IFactory {
    	@Override
    	public IRun createRun(){
    		return new FourRun();
    	}
    	
    	@Override
    	public IPacking createPacking() {
    		return new Shoes();
    	}
    }
    
    打印结果
    ---------------
    我四条腿跑。
    我穿东西。
    

    在这里具体工厂就是对抽象产品的多种组合,用来处理复杂的情景。也是将多种简单工厂模型组合在一起实现复杂功能。

    工厂模式总结

    工厂模式就是产品需要通过工厂生产。这也就决定了它的特点-产品与工厂耦合。因为工厂直接生成了产品的实例,拓展性很差,每次拓展新产品,都需要修改工厂或者添加新的工厂。

    所以这里就想到了策略模式,它们有很多相似之处,但策略模式却是解耦和的。

    展开全文
  • 设计模式之策略模式

    2017-05-16 15:00:00
    原因是代码中用了几种设计模式,而我对常用的几种设计模式不熟悉,所以导致看别人调来调去的代码很费劲。正好这几天工作不是特别忙,抓紧时间恶补下相关知识(我看的是《大话设计模式》这本书)。 今天介绍的是策略...
  • 其格式不固定,一般有以下几种: 1、条文式 条文式也称条款式,是用序数词给每一自然段编号的*格式。通过给每个自然段编号,总结被分为几个问题,按问题谈情况和体会。这种格式有灵活,方便的特点。 2、两段式 ...
  • C#中数据类型

    2019-10-16 21:15:10
    1.C#常用数据类型: int...2.在 C# 中,变量分为以下几种类型(按存储方式,指针类型除外): 值类型(Value types) 引用类型(Reference types) 指针类型(Pointer types) 值类型源于System.ValueType家族,每...
  • 家风也分为几种,在家里做的事、在家里做家务等等,在家里做的事情的是好家风。家风也叫门风,是一个家庭或家族的传统风尚。 家规很严格的,所以家里的规则必须要严格遵守一个家庭所规定的行为规范,一般是由一个...
  • C语言中基本整型数据类型

    千次阅读 2014-03-26 21:05:32
    C语言中的基本整型数据类型 整型家族包括字符、短整型、整型、长整型,它们都分为有符号和...long,unsigned long pointer为机器全字长,其实也就是这几种类型的大小和CPU的位数是一样的。 下面的程序是在X86架构环境
  • 细胞死亡是生命现象不可逆停止及生命的结束,正常的组织中经常发生细胞死亡,是维持组织机能和形态所必须的,常见的细胞死亡原因及方式主要有以下几种: 生存还是死亡,其实细胞家族每天都在做着这样的选择——不仅...
  • 文本编辑器(1.0)

    2018-05-13 16:43:58
    linux是一文本驱动的操作系统。用户在使用linux过程中经常需要编辑文本,如编写脚本文件...linux提供了一个完整的编辑器家族系列,如Ed、Ex、vi和Emacs等,按功能可以将其分为两大类:行编辑器(Ed、Ex)和全屏编...
  • 上一篇我们介绍了可视化表示数据集中各变量间关系的基本方法。...1 前言在 seaborn 中,有几种不同的方法可以对分类数据进行可视化。在这里我们将不同的分类图类型视为三个不同的家族,下面我们将详...
  • Json语法基本解析

    2021-02-09 00:49:42
    本小节内容主要分为以下个方面来介绍: >JSON的身份证 >JSON的数据格式 >JSON的解析方向 一、JSON的身份证 全名:JavaScript Object Notation 户籍:Json是一轻量级数据交换格式,它采用的是完全独立...
  • C++模板学习

    2020-02-17 15:12:41
    模板初阶 泛型编程 函数重载的个不好的地方: 1.代码的复用率低,新类型出现时,就需要增加对应的函数。例如交换函数的书写时,就能体现出复用率低。...概念:函数模板代表了一个函数家族,该函...
  • 维生素是一个庞大的家族,就目前所知的维生素就有,大致可分为脂溶性和水溶性两大类。前者包括维生素A、D、E、K,后一类包括维生素B族和维生素C,以及许多“类维生素”。 由于现在人群缺乏各种维生素的现象...
  • 各种维生素作用一览

    2009-06-26 18:34:00
    维生素是个庞大的家族,就目前所知的维生素就有,大致可分为脂溶性和水溶性两大类。前者包括维生素A、D、E、K,后一类包括维生素B族和维生素C,以及许多“类维生素”。现在医学上发现的维生素主要有: 脂溶性...
  • 数据结构05----C语言树

    2020-09-01 19:46:22
    前面节的内容,链接如下: 单链表 双链表 栈 队列 今天我们来看看数据结构中的另外一个重要内容:树 六、树 前面我们学习的都是线性结构,现在说的树属于一非线性结构。树的模型,类似于一个家族的族谱,相信...
  • 7.15 几种高可靠的工控机软件故障自动重启动技术 7.16 电磁波干扰与塑料机箱屏蔽 第八章 应用开发中的经验与体会 8.1 8051单片机开发的几点经验 8.2 微机测控系统设计中应重视的两个问题 8.3 谈谈...
  • 例如,一个家族中的族谱关系如图1-1所示: A有后代B,C;B有后代D,E;C有后代F。 典型的二叉树如图1-1所示: 详细讲解二叉树的基本概念,见表1-2。 图1-1 二叉树图 表1-2 二叉树的基本概念 父结父结点(根) 在树...
  • C#数据结构

    2013-12-10 11:49:54
    数据项分为,一叫做初 等项,如学生的性别、籍贯等,在处理时不能再进行分割;另一叫做组合项, 如学生的成绩,它可以再分为数学、物理、化学等更小的项。 3、数据对象(Data Object) 数据对象是性质相同的...
  • 当前的发展是软件家族法 ,即产品线方法。多视点方法也是管理需求变化的一新方法,它可以用于管理不一致性, 并进行关于变化的推理。 2. M公司的软件产品以开发实验型的新软件为主。用瀑布模型进行软件开发已经有...
  • IntelCPU命名规则

    2008-12-11 09:31:05
    后缀"C":表示这是Northwood核心、512KB二级缓存、800MHz FSB、支持超线程技术的产品,共有2.4C GHz、2.6C GHz、2.8C GHz、3.0C GHz、3.2C GHz和3.4C GHz等几种。 后缀"E":表示这是Prescott核心、1MB二级缓存、...
  • 实例053 获取当前日期是星期 86 实例054 获取当前年的天数 87 实例055 获取当前月的天数 88 实例056 计算两日期时间间隔 90 2.7 C#语言高级应用 91 实例057 一无所有——细说可空类型 91 实例058 半壁江山——全角...
  • 分为两个部分,这是第一部分。 本书由浅入深、循序渐进地介绍了Windows驱动程序的开发方法与调试技巧。本书共分23章,内容涵盖了 Windows操作系统的基本原理、NT驱动程序与WDM驱动程序的构造、驱动程序中的同步...
  • 实例053 获取当前日期是星期 86 实例054 获取当前年的天数 87 实例055 获取当前月的天数 88 实例056 计算两日期时间间隔 90 2.7 C#语言高级应用 91 实例057 一无所有——细说可空类型 91 实例058 半壁江山——全角...
  • 实例053 获取当前日期是星期 86 实例054 获取当前年的天数 87 实例055 获取当前月的天数 88 实例056 计算两日期时间间隔 90 2.7 C#语言高级应用 91 实例057 一无所有——细说可空类型 91 实例058 半壁江山——全角...
  • 全书分为两个部分,共14章,第一部分是集群理论篇,这部分从集群基础知识入手,通过分析集群环境和单机环境的不同,介绍了集群环境的各个组件及其作用,以及集群环境的一些专有技术,包括oracle clusterware、oracle...
  • flash shiti

    2014-03-14 10:32:41
    37.比较运算符分为几种? A. 数值比较运算符 B. 字串比较运算符 C. 字母比较运算符 D. 汉字比较运算符 38.在声音同步类型中包括哪几种类型? A. Event B. Start C. Stop D. Stream 39.以下操作哪几项...
  • 客家民系,开始他们生活在四面封建割据的小王朝包围之中,基本上不与土著居民交往,长期过着以家族为核心的集体生活,宗族观念很强,多次迁徙和重建家园的劳动,培养了他们刻苦耐劳的性格和一定的“山地意识”,后与...
  • 入门学习Linux常用必会60个命令实例详解doc/txt

    千次下载 热门讨论 2011-06-09 00:08:45
    建议在/mnt里建个/mnt/cdrom、/mnt/floppy、/mnt/mo等目录,当作目录的专用挂载点。举例而言,如要挂载下列5个设备,其执行指令可能如下 (假设都是Linux的ext2系统,如果是Windows XX请将ext2改成vfat): 软盘 ==...

空空如也

空空如也

1 2
收藏数 30
精华内容 12
关键字:

家族分为几种