1 定义:
1.1 定义:Decouple an abstraction from its implementation so that two can vary independently.(将抽象和实现解耦,使得两者独立地变化。)
1.2 通用类图:
1.3 通用代码:
public interface Implementor { // 基本方法 public void doSomething(); public void doAnything(); } public class ConcreteImplementor1 implements Implementor { public void doSomething() { // 业务逻辑处理 } public void doAnything() { // 业务逻辑处理 } } public class ConcreteImplementor2 implements Implementor { public void doSomething() { // 业务逻辑处理 } public void doAnything() { // 业务逻辑处理 } } public abstract class Abstraction { // 定义对实现化角色的引用 private Implementor imp; // 约束子类必须实现该构造函数 public Abstraction(Implementor _imp) { this.imp = _imp; } // 自身的行为和属性 public void request() { this.imp.doSomething(); } // 获得实现化角色 public Implementor getImp() { return imp; } } public class RefinedAbstraction extends Abstraction { // 覆写构造函数 public RefinedAbstraction(Implementor _imp) { super(_imp); } // 修正父类的行文 @Override public void request() { /* * 业务处理.... */ super.request(); super.getImp().doAnything(); } } public class Client { public static void main(String[] args) { // 定义一个实现化角色 Implementor imp = new ConcreteImplementor1(); // 定义一个抽象化角色 Abstraction abs = new RefinedAbstraction(imp); // 执行行文 abs.request(); } }
2.1 抽象与实现分离:实现不用再绑定在一个固定的抽象层次上;
2.2 实现细节对客户透明:实现已经由抽象层通过聚合关系完成了封装。
3 缺点
暂无
4 应用场景
4.1 不希望或不适用使用继承的场合:如继承层次过渡,无法更细化设计颗粒等场景;
4.2 接口或抽象类不稳定的场景:
4.3 重用性要求较高的场景:采用继承则受父类的限制,不可能出现较细的粒度。
5 注意事项
主要考虑如何拆分抽象和实现,并不是一涉及继承就要考虑使用该模式。其意图是对变化的封装,尽量把变化的因素封装到最细、最小的逻辑单元中,避免风险扩散。
尤其在多层继承时,要首先考虑。
6 扩展
暂无
7 范例
7.1 公司生产产品为例:(最初版,公司与产品紧耦合)
类图如下:
源码如下:
public abstract class Corp { /* * 是公司就应该有生产把,甭管是什么软件公司还是制造业公司 那每个公司的生产的 * 东西都不一样,所以由实现类来完成 */ protected abstract void produce(); /* * 有产品了,那肯定要销售呀,不销售你公司怎么生存 */ protected abstract void sell(); // 公司是干什么的?赚钱的呀,不赚钱傻子才干 public void makeMoney() { // 每个公司都是一样,先生产 this.produce(); // 然后销售 this.sell(); } } public class HouseCorp extends Corp { // 房地产公司就是盖房子 protected void produce() { System.out.println("房地产公司盖房子..."); } // 房地产卖房子,自己住那可不赚钱 protected void sell() { System.out.println("房地产公司出售房子..."); } // 房地产公司很High了,赚钱,计算利润 public void makeMoney() { super.makeMoney(); System.out.println("房地产公司赚大钱了..."); } } public class ClothesCorp extends Corp { // 服装公司生产的就是衣服了 protected void produce() { System.out.println("服装公司生产衣服..."); } // 服装公司卖服装,可只卖服装,不卖穿衣服的模特 protected void sell() { System.out.println("服装公司出售衣服..."); } // 服装公司不景气,但怎么说也是赚钱行业 public void makeMoney() { super.makeMoney(); System.out.println("服装公司赚小钱..."); } } public class Client { public static void main(String[] args) { System.out.println("-------房地产公司是这个样子运行的-------"); // 先找到我的公司 HouseCorp houseCorp = new HouseCorp(); // 看我怎么挣钱 houseCorp.makeMoney(); System.out.println("\n"); System.out.println("-------服装公司是这样运行的-------"); ClothesCorp clothesCorp = new ClothesCorp(); clothesCorp.makeMoney(); } }
类图不变:
源码改变如下:
public class IPodCorp extends Corp { // 我开始生产iPod了 protected void produce() { System.out.println("我生产iPod..."); } // 山寨的iPod很畅销,便宜呀 protected void sell() { System.out.println("iPod畅销..."); } // 狂赚钱 public void makeMoney() { super.makeMoney(); System.out.println("我赚钱呀..."); } } public class Client { public static void main(String[] args) { System.out.println("-------房地产公司是这个样子运行的-------"); // 先找到我的公司 HouseCorp houseCorp = new HouseCorp(); // 看我怎么挣钱 houseCorp.makeMoney(); System.out.println("\n"); System.out.println("-------山寨公司是这样运行的-------"); IPodCorp iPodCorp = new IPodCorp(); iPodCorp.makeMoney(); } }整个的变化了,也即原本“管理,赚钱方式”这些 不用改变的,也被推倒重来了。。。
7.3 公司生产产品为例:(更改为关联版,公司与产品仅关联)
类图如下:
源码如下:
public abstract class Product { // 甭管是什么产品它总要是能被生产出来 public abstract void beProducted(); // 生产出来的东西,一定要销售出去,否则亏本呀 public abstract void beSelled(); } public class House extends Product { // 豆腐渣就豆腐渣呗,好歹也是个房子 public void beProducted() { System.out.println("生产出的房子是这个样子的..."); } // 虽然是豆腐渣,也是能够销售出去的 public void beSelled() { System.out.println("生产出的房子卖出去了..."); } } public class IPod extends Product { public void beProducted() { System.out.println("生产出的iPod是这个样子的..."); } public void beSelled() { System.out.println("生产出的iPod卖出去了..."); } } public abstract class Corp { // 定义一个产品对象,抽象的了,不知道具体是什么产品 private Product product; // 构造函数,由子类定义传递具体的产品进来 public Corp(Product product) { this.product = product; } // 公司是干什么的?赚钱的呀,不赚钱傻子才干 public void makeMoney() { // 每个公司都是一样,先生产 this.product.beProducted(); // 然后销售 this.product.beSelled(); } } public class HouseCorp extends Corp { // 定义传递一个House产品进来 public HouseCorp(House house) { super(house); } // 房地产公司很High了,赚钱,计算利润 public void makeMoney() { super.makeMoney(); System.out.println("房地产公司赚大钱了..."); } } public class ShanZhaiCorp extends Corp { // 产什么产品,不知道,等被调用的才知道 public ShanZhaiCorp(Product product) { super(product); } // 狂赚钱 public void makeMoney() { super.makeMoney(); System.out.println("我赚钱呀..."); } } public class Client { public static void main(String[] args) { House house = new House(); System.out.println("-------房地产公司是这个样子运行的-------"); // 先找到房地产公司 HouseCorp houseCorp = new HouseCorp(house); // 看我怎么挣钱 houseCorp.makeMoney(); System.out.println("\n"); // 山寨公司生产的产品很多,不过我只要指定产品就成了 System.out.println("-------山寨公司是这样运行的-------"); ShanZhaiCorp shanZhaiCorp = new ShanZhaiCorp(new IPod()); shanZhaiCorp.makeMoney(); } }
7.4 公司生产产品为例:(最终版,产品又变回衣服时)
类图与上类似:
源码如下:
public class Client { public static void main(String[] args) { House house = new House(); System.out.println("-------房地产公司是这个样子运行的-------"); // 先找到房地产公司 HouseCorp houseCorp = new HouseCorp(house); // 看我怎么挣钱 houseCorp.makeMoney(); System.out.println("\n"); // 山寨公司生产的产品很多,不过我只要指定产品就成了 System.out.println("-------山寨公司是这样运行的-------"); ShanZhaiCorp shanZhaiCorp = new ShanZhaiCorp(new Clothes()); shanZhaiCorp.makeMoney(); } }
此时,仅改变产品参数。