前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >设计模式- 合成/组合原则

设计模式- 合成/组合原则

作者头像
高广超
发布于 2018-12-12 03:12:45
发布于 2018-12-12 03:12:45
53600
代码可运行
举报
文章被收录于专栏:互联网技术栈互联网技术栈
运行总次数:0
代码可运行

《Effective Java》

复合优先于继承

与方法调用不同的是,继承打破了封装性。

上面的问题都来源于对方法的改写动作。如果你在扩展一个类的时候,仅仅是增加新的方法,而不改写已有的方法,你可能会认为这样做是安全的,但是也并不是完全没有风险。

有一种办法可以避免前面提到的所有问题,你不再是扩展一个已有的类,而是在新的类中增加一个私有域,他引用了这个已有的类的一个实例。这种设计被称作复合。

代码语言:javascript
代码运行次数:0
运行
复制
 public class InstrumentedSet<E> extends ForwardingSet<E> {
    private int addCount = 0;
 
    public InstrumentedSet(Set<E> s) {
        super(s);   
    }
     
    public boolean add(E e) {
        addCount++;
        return super.add(e);
    }
 
    public boolean addAll(Collection<? extends E> c) {
        addCount += c.size();
        return super.addAll(c);
    }
 
    public int getAddCount() {
        return addCount;
    }
}
 
 
public class ForwardingSet<E> implements Set<E> {
    private final Set s;
    public ForwardingSet(Set<E> s) {
        this.s = s;   
    }
 
    public void add(E e) { return s.add(e); }
    // ......
}

应为原有已有的类边成了一个新类的一个组成部分。新类中的每个实例方法都可以被调用被包含的已有实例中对应的方法,并返回它的结果。这被称为转发,新类中的方法被称为转发方法。这样的到的类会非常稳固,他不依赖于已有类的事现细节。

每一个InstrumentedSet实例都把另一个Set实例包装起来,所以InstrumentedSet类被称作包装类。(Decorutor模式)

包装类不适合用在回调框架中,在回调框架中,对象把自己的引用传递给其他的对象, 已便将来调用回来,因为被包装起来的对象并不知道他外面的包装对象,所以他传递一个只向自己的引用,回调时绕开了外面的包装对象这被称为SELF问题。

只有当子类真正是超类的子类型的时候,继承才是合适的,对于正在扩展的类,继承机制会把超类API中的所有缺陷传播到子类中,而复合技术运允许你设计一个新的API从而隐藏这些缺陷。


《Java与模式》

一、什么是合成/聚合复用原则?

合成/聚合复用原则是在一个新的对象里面使用一些已有的对象,使之成为新对象的一部分;新的对象通过向这些对象的委派达到复用已有功能的目的

简述为:要尽量使用合成/聚合,尽量不要使用继承。

二、合成和聚合的区别;依赖和关联

合成(Composition)和聚合(Aggregation)都是关联(Association)的特殊种类。用C语言来讲,合成是值的聚合(Aggregation by Value),聚合是则是引用的聚合(Aggregation by Reference)。

(1)聚合用来表示“拥有”关系或者整体与部分的关系。

代表部分的对象有可能会被多个代表整体的对象所共享,而且不一定会随着某个代表整体的对象被销毁或破坏而被销毁或破坏,部分的生命周期可以超越整体。例如,班级和学生,当班级删除后,学生还能存在,学生可以被培训机构引用。

聚合关系UML类图

image.png

代码语言:javascript
代码运行次数:0
运行
复制
class Student {
}
class Classes{
        privateStudent student;
        publicClasses(Student student){
                  this.student=student;
       }
}

(2)合成用来表示一种强得多的“拥有”关系。

在一个合成关系里,部分和整体的生命周期是一样的。一个合成的新对象完全拥有对其组成部分的支配权,包括它们的创建和湮灭等。使用程序语言的术语来说,合成而成的新对象对组成部分的内存分配、内存释放有绝对的责任。

一个合成关系中的成分对象是不能与另一个合成关系共享的。一个成分对象在同一个时间内只能属于一个合成关系。如果一个合成关系湮灭了,那么所有的成分对象要么自己湮灭所有的成分对象(这种情况较为普遍)要么就得将这一责任交给别人(较为罕见)。

例如,一个人由头、四肢和各种器官组成,人与这些具有相同的生命周期,人死了,这些器官也就挂了。房子和房间的关系,当房子没了,房间也不可能独立存在。 合成关系UML类图

image.png

代码语言:javascript
代码运行次数:0
运行
复制
class Room{
         public Room createRoom(){
                    System.out.println(“创建房间”);
                   returnnew Room();
          }
 }
class House{
         private Room room;
         public House(){
                room=new Room();
          }
          public void createHouse(){
                room.createRoom();
         }
  }

(3)依赖和关联

依赖(Dependency)

依赖是类与类之间的连接,表示一个类依赖于另外一个类的定义。依赖关系仅仅描述了类与类之间的一种使用与被使用的关系,在Java中体现为局部变量、方法的参数或者是对静态方法的调用。

依赖关系UML类图

image.png

代码语言:javascript
代码运行次数:0
运行
复制
static class Boat{ 
       public static void row(){ 
           System.out.println("开动"); 
       } 
} 
class Person{ 
        public void crossRiver(Boatboat){ 
            boat.row(); 
        } 
         
        public void fishing(){ 
            Boat boat =new Boat() ; 
            boat.row(); 
        }
       public void patrol(){ 
            Boat.row() ; 
       } 
} 
关联(Association)

关联是类与类之间的连结。关联关系使一个类知道另外一个类的属性和方法。关联可以是双向的,也可以是单向的。体现在Java中,关联关系是通过成员变量来实现的。 一般关联关系UML类图

image.png

代码语言:javascript
代码运行次数:0
运行
复制
class Computer{ 
    public void develop(){ 
       System.out.println("Develop "); 
    } 
} 
class Person{ 
       private Computer computer ; 
         
       public Person(Computer computer){ 
           this.computer = computer ; 
       } 
         
       public void work(){ 
           computer.develop() ; 
           System.out.println("work"); 
       } 
 } 

三、为什么使用合成/聚合复用,而不使用继承复用?

在面向对象的设计里,有两种基本的方法可以在不同的环境中复用已有的设计和实现,即通过合成/聚合复用和通过继承复用。两者的特点和区别,优点和缺点如下。

1、合成/聚合复用

由于合成或聚合可以将已有对象纳入到新对象中,使之成为新对象的一部分,因此新对象可以调用已有对象的功能。这样做的好处有

  • (1) 新对象存取成分对象的唯一方法是通过成分对象的接口。
  • (2) 这种复用是黑箱复用,因为成分对象的内部细节是新对象看不见的。
  • (3) 这种复用支持包装。
  • (4) 这种复用所需的依赖较少。
  • (5) 每一个新的类可以将焦点集中到一个任务上。
  • (6) 这种复用可以再运行时间内动态进行,新对象可以动态地引用与成分对象类型相同的对象。

一般而言,如果一个角色得到了更多的责任,那么可以使用合成/聚合关系将新的责任委派到合适的对象。当然,这种复用也有缺点。最主要的缺点就是通过这种复用建造的系统会有较多的对象需要管理。

2、继承复用

继承复用通过扩展一个已有对象的实现来得到新的功能,基类明显的捕获共同的属性和方法,而子类通过增加新的属性和方法来扩展超类的实现。继承是类型的复用。

继承复用的优点。

  • (1)新的实现较为容易,因为超类的大部分功能可以通过继承关系自动进入子类。
  • (2)修改或扩展继承而来的实现较为容易。

继承复用的缺点。

  • (1)继承复用破坏包装,因为继承将超类的实现细节暴露给了子类。因为超类的内部细节常常对子类是透明的,因此这种复用是透明的复用,又叫“白箱”复用。
  • (2)如果超类的实现改变了,那么子类的实现也不得不发生改变。因此,当一个基类发生了改变时,这种改变会传导到一级又一级的子类,使得设计师不得不相应的改变这些子类,以适应超类的变化。
  • (3)从超类继承而来的实现是静态的,不可能在运行时间内发生变化,因此没有足够的灵活性。

由于继承复用有以上的缺点,所有尽量使用合成/聚合而不是继承来达到对实现的复用,是非常重要的设计原则。

四、从代码重构的角度理解

一般来说,对于违反里氏代换原则的设计进行重构时,可以采取两种方法:一是加入一个抽象超类;二是将继承关系改写为合成/聚合关系。

要正确的使用继承关系,必须透彻的理解里氏代换原则和Coad条件。

区分“Has-A”和“Is -A”

“Is-A”是严格的分类学意义上的定义,意思是一个类是另以个类的“一种”。而“Has-A”表示某一个角色具有某一项责任。

导致错误的使用继承而不是合成/聚合的一个常见原因是错误的把“Has-A”当做“Is-A”。“Is-A”代表一个类是另一个类的一种;“Has-A”代表一个类是另一个类的一个角色,而不是另一个类的一个特殊种类。这是Coad条件的第一条。

下面类图中描述的例子。“人”被继承到“学生”、“经理”和“雇员”等子类。而实际上,学生”、“经理”和“雇员”分别描述一种角色,而“人”可以同时有几种不同的角色。比如,一个人既然是“经理”,就必然是“雇员”;而“人”可能同时还参加MBA课程,从而也是一个“学生”。使用继承来实现角色,则只能使每一个“人”具有Is-A角色,而且继承是静态的,这会使得一个“人”在成为“雇员”身份后,就永远为“雇员”,不能成为“学生”和“经理”,而这显然是不合理的。

image.png

这一错误的设计源自于把“角色”的等级结构和“人”的等级结构混淆起来,把“Has-A”角色误解为“Is -A”角色。因此要纠正这种错误,关键是区分“人”与“角色”的区别。下图所示的的设计就正确的做到了这一点。

image.png

从上图可以看出,每一个“人”都可以有一个以上的“角色”,所有一个“人”可以同时是“雇员”,又是“经理”,甚至同时又是“学生”。而且由于“人”与“角色”的耦合是通过合成的,因此,角色可以有动态的变化。一个“人”可以开始是“雇员”,然后晋升为“经理”,然后又由于他参加了MBA课程,又称为了“学生“。

当一个类是另一个类的角色时,不应当使用继承描述这种关系。

与里氏代换原则联合使用

里氏代换原则是继承复用的基石。如果在任何可以使用B类型的地方都可以使用S类型,那么S类型才可以称为B类型的子类型(SubType),而B类型才能称为S类型的基类型(BaseType)。

换言之,只有当每一个S在任何情况下都是一种B的时候,才可以将S设计成B的子类。如果两个类的关系是“Has-A”关系而不是“Is -A”,这两个类一定违反里氏代换原则。 只有两个类满足里氏代换原则,才有可能是“Is -A”关系。


本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017.04.13 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
算法大佬看了流泪,为什么这么好的CTR预估总结之前没分享(上篇)
在广告、推荐系统CTR预估问题上,早期的完全规则方法被过渡到以LR为代表的机器学习方法,为了充分发挥组合特征的价值,在相当长一段时间里,业界热衷于使用LR+人工特征工程。但人工组合特征成本高昂 ,在不同任务上也难以复用。2010年FM因子分解方法的出现解决了人工组合特征的困境,2014年Facebook提出的GBDT+LR也给出了一种利用树模型特点构建组合特征的思路。不过随着深度学习的崛起,2015年以后,借助非线性自动组合特征能力的深度模型,开始成为业内的主流。从经典DNN到结合浅层的Wide&Deep,用于CTR预估的深度模型在近些年间百花盛开,各种交叉特征建模方法层出不穷,Attention机制也从其他研究领域引入,帮助更好的适应业务,提升模型的解释性。在这进化路线之下,核心问题离不开解决数据高维稀疏难题,自动化组合特征,模型可解释。我们梳理了近些年CTR预估问题中有代表性的模型研究/应用成果,并对部分经典模型的实现原理进行详细剖析,落成文字作为学习过程的记录。
炼丹笔记
2021/05/14
5.3K0
算法大佬看了流泪,为什么这么好的CTR预估总结之前没分享(上篇)
Facebook 面向个性化推荐系统的深度学习推荐模型
Deep Learning Recommendation Model for Personalization and Recommendation Systems
Datawhale
2019/10/18
9530
DeepFM
特征交叉对于CTR问题的求解有着重要作用,纵观CTR模型的发展可以看出,每一次效果的提升,都伴随着对特征的挖掘,尤其是交叉特征。FM[1]算法在线性模型LR的基础上增加了二阶特征的交叉,对LR效果有着显著的提升;随着深度学习的发展,深度模型天然的特征交叉能力,Google的Wide & Deep[2]通过结合Wide模型的记忆能力和Deep模型的泛化能力,充分利用Deep侧的特征交叉能力,然而由于Wide侧使用的依然是线性模型,依赖于人工特征工程的参与。DeepFM[3]是华为在2017年提出的用于求解CTR问题的深度模型,DeepFM是在Google的Wide & Deep模型的基础上,将FM算法引入到Wide侧,替换掉原始的Wide & Deep模型中的LR模型,可以实现端到端的学习特征的交叉,无需人工特征工程的参与。DeepFM模型一经推出,就受到业界很多公司的关注,并在众多互联网公司的多个场景中落地。
felixzhao
2022/05/12
4740
DeepFM
深度CTR预估模型的演化之路2019最新进展
导读:本文主要介绍深度CTR经典预估模型的演化之路以及在2019工业界的最新进展。
AI科技大本营
2019/11/12
9670
深度CTR预估模型的演化之路2019最新进展
深度学习在CTR预估中的应用
深度学习凭借其强大的表达能力和灵活的网络结构在NLP、图像、语音等众多领域取得了重大突破。在广告领域,预测用户点击率(Click Through Rate,简称CTR)领域近年也有大量关于深度学习方面的研究,仅这两年就出现了不少于二十多种方法。本文就近几年CTR预估领域中学术界的经典方法进行探究, 并比较各自之间模型设计的初衷和各自优缺点。通过十种不同CTR深度模型的比较,不同的模型本质上都可以由基础的底层组件组成。
鹅厂优文
2018/04/20
4.7K10
深度学习在CTR预估中的应用
Wide&Deep、DCN、xDeepFM、DIN、GateNet、IPRec…你都掌握了吗?一文总结推荐系统必备经典模型(三)
 机器之心专栏 本专栏由机器之心SOTA!模型资源站出品,每周日于机器之心公众号持续更新。 本专栏将逐一盘点自然语言处理、计算机视觉等领域下的常见任务,并对在这些任务上取得过 SOTA 的经典模型逐一详解。前往 SOTA!模型资源站(sota.jiqizhixin.com)即可获取本文中包含的模型实现代码、预训练模型及 API 等资源。 本文将分 3 期进行连载,共介绍 18 个在推荐系统任务上曾取得 SOTA 的经典模型。 第 1 期:DSSM、Youtube_DNN、SASRec、PinSAGE、TDM
机器之心
2023/04/06
1.6K0
Wide&Deep、DCN、xDeepFM、DIN、GateNet、IPRec…你都掌握了吗?一文总结推荐系统必备经典模型(三)
主流CTR预估模型的演化及对比
学习和预测用户的反馈对于个性化推荐、信息检索和在线广告等领域都有着极其重要的作用。在这些领域,用户的反馈行为包括点击、收藏、购买等。本文以点击率(CTR)预估为例,介绍常用的CTR预估模型,试图找出它们之间的关联和演化规律。
数说君
2019/07/17
1.1K0
主流CTR预估模型的演化及对比
网易如何做新闻推荐:深度学习排序系统及模型
深度学习的概念源于人工神经网络的研究。深度学习通过组合低层特征形成更加抽象的高层表示属性类别或特征,以发现数据的有效表示,而这种使用相对较短、稠密的向量表示叫做分布式特征表示(也可以称为嵌入式表示)。本部分主要对于目前使用较广的一些学习算法进行一个简单的回顾。
机器学习AI算法工程
2019/10/28
1.4K0
网易如何做新闻推荐:深度学习排序系统及模型
[源码解析] NVIDIA HugeCTR,GPU版本参数服务器--- (5) 嵌入式hash表
在这篇文章中,我们介绍了 HugeCTR,这是一个面向行业的推荐系统训练框架,针对具有模型并行嵌入和数据并行密集网络的大规模 CTR 模型进行了优化。
罗西的思考
2022/05/09
1.4K0
[源码解析] NVIDIA HugeCTR,GPU版本参数服务器--- (5) 嵌入式hash表
Neural Factorization Machines(NFM)
Neural Factorization Machines(NFM)[1]是在2017年提出的用于求解CTR问题的算法模型,在Wide & Deep模型被提出后,相继出现了一些改进的算法模型,如DeepFM和DCN可以看成是对于Wide & Deep模型中Wide部分的改进,而此处的NFM模型则是可以看作是对Deep部分的改进。从模型的名字来看,NFM包含了两个部分,第一为Neural,这部分与神经网络相关,第二为Factorization Machines,这部分与FM相关。对于FM模型,文章中提到了可以从深度学习网络结构的角度来看待,此时FM就可以看作是由单层LR和二阶特征交叉组成的Wide & Deep模型,与Google提出的Wide & Deep模型的不同之处就是Deep部分是二阶隐向量相乘。从这个角度上来看,NFM是在FM的基础上利用NN模型代替FM中的Deep部分,而这个NN与Wide & Deep中的Deep的不同是NFM中的Deep中包含了Bi-Interaction的层,用于对特征做二阶交叉运算。综上,NFM的优化点主要为:
felixzhao
2022/05/12
6370
Neural Factorization Machines(NFM)
KDD 2019高维稀疏数据上的深度学习Workshop论文汇总
【导读】本文是“深度推荐系统”专栏的第九篇文章,这个系列将介绍在深度学习的强力驱动下,给推荐系统工业界所带来的最前沿的变化。本文简要总结一下阿里妈妈在 KDD 2019 上组织的第一届面向高维稀疏数据的深度学习实践 Workshop[1] 收录的论文。
AI科技大本营
2019/08/29
1.2K0
CTR学习笔记&代码实现3-深度ctr模型 FNN->PNN->DeepFM
这一节我们总结FM三兄弟FNN/PNN/DeepFM,由远及近,从最初把FM得到的隐向量和权重作为神经网络输入的FNN,到把向量内/外积从预训练直接迁移到神经网络中的PNN,再到参考wide&Deep框架把人工特征交互替换成FM的DeepFM,我们终于来到了2017年。。。
风雨中的小七
2020/04/24
1.8K6
CTR学习笔记&代码实现3-深度ctr模型 FNN->PNN->DeepFM
干货|深度学习在CTR中的应用
作者:jediael_lu
fishexpert
2018/11/21
1.4K0
从Wide and Deep、DeepFM到DLRM,现代的推荐系统算法研究
2019年5月,Facebook开放了他们的一些推荐方法,并引入了DLRM(深度学习推荐模型)。这篇文章旨在解释DLRM和其他现代推荐方法是如何以及为什么能够如此出色地工作的,通过研究它们是如何从该领域以前的结果中衍生出来的,详细解释它们的内部工作原理和思路。
deephub
2021/02/12
2.1K0
从Wide and Deep、DeepFM到DLRM,现代的推荐系统算法研究
FNN: Deep Learning over Multi-field Categorical Data
原论文:Deep learning over multi-field categorical data
用户3578099
2020/09/29
1.1K0
FNN: Deep Learning over Multi-field Categorical Data
谷歌、阿里们的杀手锏:三大领域,十大深度学习CTR模型演化图谱
今天我们一起回顾一下近3年来的所有主流深度学习CTR模型,也是我工作之余的知识总结,希望能帮大家梳理推荐系统、计算广告领域在深度学习方面的前沿进展。
AI科技大本营
2019/07/03
1.1K0
谷歌、阿里们的杀手锏:三大领域,十大深度学习CTR模型演化图谱
深度学习基础知识 | 上
MLP网络是一种应用最为广泛的一种网络,其中DNN就是属于MLP网络,它是一个前向结构的人工神经网络,输入一组向量向前传播输出向量,网络结构如下:
昱良
2019/07/04
6790
点击率预测模型Embedding层的学习和训练
​导读:本文将简要介绍推荐模型的发展历史,现状,和下一步的研究趋势。并重点介绍针对embedding数据的模型训练及优化。主要包含以下几大部分内容:
DataFunTalk
2022/05/04
1.4K0
Deep&Cross Network(DCN)
Deep&Cross Network(DCN)[1]是由Google于2017年提出的用于计算CTR问题的方法,是对Wide&Deep[2]模型的进一步改进。线性模型无法学习到特征的交叉属性,需要大量的人工特征工程的介入,深度网络对于交叉特征的学习有着天然的优势,在Wide&Deep模型中,Deep侧已经是一个DNN模型,而Wide侧是一个线性模型LR,无法有效的学习到交叉特征。在DCN中针对Wide&Deep模型的Wide侧提出了Cross网络,通过Cross网络学习到更多的交叉特征,提升整个模型的特征表达能力。
felixzhao
2022/05/12
1.4K0
Deep&Cross Network(DCN)
揭秘Facebook增长引擎——深度学习推荐系统
一些最前沿的研究成果大多来自业界巨头的实践。从Facebook 2014年提出的GBDT+LR组合模型引领特征工程模型化的方向开始,业界迎来了深度学习推荐系统应用的浪潮。
博文视点Broadview
2020/06/10
1.5K0
推荐阅读
相关推荐
算法大佬看了流泪,为什么这么好的CTR预估总结之前没分享(上篇)
更多 >
目录
  • 《Effective Java》
    • 复合优先于继承
  • 《Java与模式》
    • 一、什么是合成/聚合复用原则?
    • 二、合成和聚合的区别;依赖和关联
      • (1)聚合用来表示“拥有”关系或者整体与部分的关系。
      • (2)合成用来表示一种强得多的“拥有”关系。
      • (3)依赖和关联
      • 依赖(Dependency)
    • 三、为什么使用合成/聚合复用,而不使用继承复用?
      • 1、合成/聚合复用
      • 2、继承复用
    • 四、从代码重构的角度理解
      • 区分“Has-A”和“Is -A”
      • 与里氏代换原则联合使用
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档