前言:
该模式采用的是组合/聚合原则。对象的继承关是静态的在编译阶段已经定义,无法在运行时改变从父类继承来的实现。子类的实现和父类之间有非常紧密的依赖关系,以至于父类的任何修改都会影响到子类的行为。当继承来的实现部满足子类的需求,要么重写父类的实现,也么被更合时的类替换,要么修改父类的实现。这种依赖关系限制了灵活性和服用性。PS:子类没有办法复用父类现有的实现,需要重写实现,导致父类无法服用。修改父类方法存在一定的风险,不是最有决绝方案。
合成聚合关系隶属于关联关系。
聚合表示一种弱的拥有关系体现形式为A对象可以包含B对象,但是B对象不是A对象的一部分。
合成表示一种强的拥有关系体现了严格的部分和整体关系,部分和整体的关系具有相同的生命周期。
eg:
一个大雁有两个翅膀,翅膀和大雁属于部分和整体的关系,具有相同的生命周期,大雁和翅膀属于合成关系。
一个雁群可以有多个大雁,但是一个大雁属于一个雁群,所以大雁和雁群属于聚合关系。雁群和大雁具有不同的生命周期。
合成关系强调的是部分和整体之前的关系,可以这么理解由多个部分组成一个完整的整体。部分和整体具有相同的生命周期。
聚合关系强调的是个体和群体之间的关系,个体具有完整的特性,由每个个体组成群体,由于个体是完整的所以和群体可以具有不同的生命周期。
在实际使用中优先考虑合成聚合。这样有助于保持每个类被封装并集中在单个任务上。这样可以使类和类继承层次保持在较小的规模并且不太可能增长为不可控的庞然大物。
1.定义:将抽象部分和它的实现部分分离,是它们能够独立的演变。
2.UML:
3.理论基础:封装,多态,继承,组合聚合
4.涉及角色:
抽象角色:一般为抽象类。定义了属性以及行为。特点如下:1.该类持有抽象实现化角色的实例 2采用构造函数初始化该实例.3.由于存在构造函数,强制子类传入具体的实现化角色,也可以是抽象实现化角色
修正抽象角色:抽象角色的子类。由于父类构造函数的原因,子类必须要实现构造函数。1.当抽象实现化角色有多个具体实现时,修正抽象角色的构造函数需要指定抽象实现角色的类型来修正抽象实现化角色。2.也可以修正抽象角色的某个具体的API其实就是重写。
抽象实现化角色:一般为接口/抽象类,定义抽象角色具有的行为
具体实现化角色:抽象实现化角色的具体子类,在该角色中实现了抽象角色的行为
总结:抽象角色持有抽象实现化角色的实例。也可以这样理解抽象角色的具体实现是由抽象实现化角色来完成的
5.优点
1.抽象和实现分离,可动态实现切换。这也是该模式主要的特点。为了解决继承的缺点提出来的,该模式下实现可以不受抽象的约束。不用在绑定在一个固定的抽象层次上。实现系统可能多维度分类。每种维度都可能变化,那么将这种多维度分离出来让它们独自变化。减少之间的耦合。
2.扩展能力很好,由于抽象和实现分离。也就说有两个纬度,不管是在抽象层面还是在实现层面可以随意扩展。但是对外提供的接口需要保持不变。
3.实现细节对客户端透明。客户端不同关心细节的实现。细节已经于抽象层通过聚合关系封装
4.减少子类个数,抽象和实现时两个不同纬度,如果采用继承需要两个维度上可变化数量乘积个子类。采用该模式只需要两个维度上可变化数量和个子类。
6.缺点
7.使用场景
1.实现/抽象存在多维度的变化,即接口/抽象类不稳定的场景
2.不希望/不适合采用继承的场景。继承层次过度,无法更细化设计颗粒
3.重用香要求较高的场景。越是细化的设计,重用的可能性越大,采用继承则受父类的限制。不可能出现太细的粒度。
8.Code
//抽象角色:定义一个公司类,公司的目标时赚钱
//抽象角色 public abstract class Company { //持有抽象实现化角色实例 protected Produce produce; //TODO 定义自身属性 //强制子类将具体的抽象实现化角色传入,多实现时候必须明确具体的实现 public Company(Produce produce){ this.produce = produce; } //定义自身方法,待用抽象实现中的具体api,可以调用抽象实现中所有的api也可以调用部分api //抽象角色定义的API如果有必要会在具体修正抽象化角色中得到修正 public void makeMoeny() { produce.toMake(); produce.toSale(); } public void riskManagement(){ System.out.println("控制风险"); } //提供非子类,获得抽象实现化角色实例 public Produce getProduce(){ return this.produce; } }//修正抽象化角色:主要修正了API,山寨公司负责生产任何产品
public class CopycatCompany extends Company { //强制子类实现构造函数 public CopycatCompany(Produce produce) { super(produce); } //修正父类方法,实际上可以理解重写,但是和一般的重写有区别 //在重写的过程中调用了抽象实现化中现有api @Override public void makeMoeny() { //TODO something super.produce.saleMaterial(); super.makeMoeny(); super.produce.toSummary(); //TODO something } @Override public Produce getProduce() { return super.getProduce(); } }通过构造函数修正父类中的抽象实现化角色, public class FlatCompany extends Company { //实现抽象化角色有多个实现时,在子类中需要构造函明确指定具体的实现化角色 //即在子类中通过构造函数修正抽象角色,也可以通过setter的方式修正 //该处其实不用修正,即参数类型为父类 public FlatCompany(Flat flat) { super(flat); } //修正抽象角色 @Override public void makeMoeny() { //TODO something super.riskManagement(); super.produce.toMake(); super.produce.toSale(); super.produce.toSummary(); //TODO something } @Override public Produce getProduce() { return super.getProduce(); } } //抽象实现化角色
public abstract class Produce { //TODO 定义属性 private String type; private float price; public Produce(String type, float price){ this.type = type; this.price = price; } public String getType() { return type; } public void setType(String type) { this.type = type; } public float getPrice() { return price; } public void setPrice(float price) { this.price = price; } //TODO 定义行为 public abstract void toSale(); public abstract void toMake(); public abstract void toSummary(); public void saleMaterial(){ System.out.println("购买制作鞋的原材料"); } } //具体实现化角色 public class Flat extends Produce { public Flat(String type, float price) { super(type, price); } @Override public void toSale() { System.out.println("销售公寓"); } @Override public void toMake() { System.out.println("建造公寓"); } @Override public void toSummary() { System.out.println("统计销售数量"); } } public class Shoes extends Produce { public Shoes(String type, float price) { super(type, price); } @Override public void toSale() { System.out.println("销售运动鞋"); } @Override public void toMake() { System.out.println("生产运动鞋"); } @Override public void toSummary() { System.out.println("购买橡胶等材料"); } }客户端
public class Client { public static void main(String[] args){ Produce shoes = new Shoes("Nike",100); Flat flat = new Flat("flat", 10000); Company company = new CopycatCompany(shoes); company.makeMoeny(); System.out.println(company.getProduce().getClass().getSimpleName()); System.out.println("================="); company = new FlatCompany(flat); company.makeMoeny(); System.out.println(company.getProduce().getClass().getSimpleName()); } }
