ObjectOriented Techniques 6 ObjectOriented Design Principles References n
面向对象技术 Object-Oriented Techniques
第 6 章面向对象的设计原则 Object-Oriented Design Principles
References n [Mart 02], Robert C. Martin, Agile Software Development-Principles, Patterns, and Practices(邓辉译,敏 捷软件开发-原则、模式与实践,清华大 学出版社,2003年) 5
开始设计:正方形 public class Rectangle { private int width; private int height; public void set. Width(int w) { width = w; } public int get. Width() { return width; } public class Square public void set. Height(int h) { extends Rectangle { height = h; public void set. Width(int w) { } super. set. Width (w); public int get. Height() { super. set. Height (w); return height; } } public void set. Height(int h) { } super. set. Width (h); super. set. Height (h) ; } } 7
设计方案正确吗? public static void resize(Rectangle r) { while (r. get. Height() <= r. get. Width()) { r. set. Height(r. get. Height() + 1); } System. out. println(“It’s OK. "); } Rectangle r 1 = new Rectangle(); r 1. set. Height(5); r 1. set. Width(15); resize(r 1); Rectangle r 2 = new Square(); r 2. set. Height(5); r 2. set. Width(15); resize(r 2); ü使用父类(长方形)时,程序正常运行 ü使用子类(正方形)时,程序陷入死循环 ü设计出问题了?继承出问题了? 8
设计目标 n n n n 可扩展性 (Extensibility) 灵活性 (Flexibility) 可插入性 (Pluggability) …… 11
面向对象的基本设计原则 n LSP:Liskov替换原则 n n OCP:开放-封闭原则 n n The Interface Segregation Principle DIP:依赖倒置原则 n n The Single Responsibility Principle ISP:接口隔离原则 n n The Open-Close Principle SRP:单一职责原则 n n The Liskov Substitution Principle The Dependency Inversion Principle …… 15
设计实现 public class Door { private boolean _is. Open=false; public boolean is. Open(){ return _is. Open; } public void open(){ _is. Open = true; } public void close(){ _is. Open = false; } } public class Smart. Test { public static void main(String[] args) { Hand my. Hand = new Hand(); my. Hand. door = new Door(); my. Hand. do(); } } public class Hand { public Door door; void do() { if (door. is. Open()) door. close(); else door. open(); } } 26
解决新的需求:修改设计 public class Hand { public Door door; public Drawer drawer; void do(int item) { switch (item){ case 1: if (door. is. Open()) door. close(); else door. open(); break; public class Smart. Test { case 2: public static void main(String[] args) { if (drawer. is. Open()) Hand my. Hand = new Hand(); drawer. close(); my. Hand. door = new Door(); else drawer. open(); my. Hand. do(1); break; } } } 手被改了! 主(使用手)程序也被改了! 28
符合OCP的设计方案 public interface Excutable { public boolean is. Open(); public void open(); public void close(); } 29
新的实现 public class Door implements Excutable { public class Drawer implements Excutable { private boolean _is. Open = false; public boolean is. Open() { return _is. Open; } } public void open() { _is. Open = true; } } public void close() { _is. Open = false; } } public class Hand { public Excutable item; public class Smart. Test { void do() { public static void main(String[] args) { if (item. is. Open()) Hand my. Hand = new Hand(); item. close(); my. Hand. item = new Door(); else my. Hand. do(); item. open(); } } 30
新的需求…… 需要手去开关冰箱……? ü为冰箱实现Excutable接口 ü不需要修改任何原有的设计 和代码 public class Refrigerator implements Excutable { private boolean _is. Open = false; public boolean is. Open() { return _is. Open; } public void open() { _is. Open = true; } public void close() { _is. Open = false; } 31 }
SRP n SRP(The Single Responsibility Principle, 单一职责原则) n n 就一个类而言,应该仅有一个引起它变化的原因 有关类的职责分配问题,是面向对象设计中最 重要的基本原则 “A critical, fundamental ability in OOA/D is to skillfully assign responsibility to software components. ” Craig Larman 33
相关API-1 /** *@(#)Coffee. Maker. API. java */ public interface Coffee. Maker. API { public static Coffee. Maker. API api = null; /** * 此函数返回保温托盘的传感器状态。该传感器判断 * 咖啡壶是否放置在其上,以及壶中是否有咖啡。 */ public int get. Warmer. Plate. Status(); public static final int WARMER_EMPTY = 0; public static final int POT_EMPTY = 1; public static final int POT_NOT_EMPTY = 2; /** * 此函数返回烧水壶开关的状态。该开关是一个浮力 * 开关,可以检测到壶中的水是否还多于1/2杯。 */ public int get. Boiler. Status(); public static final int BOILER_EMPTY = 0; public static final int BOILER_NOT_EMPTY = 1; 47
相关API-2 /** * 此函数返回加热按钮的状态。加热按钮是一个接触式 * 按钮,能够记住它自己的状态。调用这个函数将返回 * 其当前状态。然后将自己的状态恢复为 * BREW_BUTTON_NOT_PUSHED。 */ public int get. Brew. Button. Status(); public static final int BREW_BUTTON_PUSHED = 0; public static final int BREW_BUTTON_NOT_PUSHED = 1; /** * 此函数开关烧水壶的加热器件 */ public void set. Boiler. State(int boiler. Status); public static final int BOILER_ON = 0; public static final int BOILER_OFF = 1; 48
相关API-3 /** * 此函数开关保温托盘的加热器件 */ public set. Warmer. Plate. State (int warmer. State); public static final int WARMER_ON = 0; public static final int WARMER_OFF = 1; /** * 此函数开关指示灯。该指示灯应当在加热结束后亮 * 起来,在用户按下加热键之后熄灭。 */ public void set. Indicator. State (int indicator. State); public static final int INDICATOR_ON = 0; public static final int INDICATOR_OFF = 1; /** * 此函数控制压力阀门。当该阀门关闭,则烧水壶中的蒸汽 *压力增大,使热水漫过咖啡末。当阀门开启,蒸汽从阀门 * 中得到释放,烧水壶中的水就不会漫过咖啡 粉末了 */ public void set. Relief. Valve. State (int relief. Valve. State); public static final int VALVE_OPEN = 0; public static final int VALVE_CLOSED = 1; } 49
泡泡类(Vapor Classes) n n 所谓泡泡类,就是没有带来任何好处的类。 考虑Light类: public class Light { public void turn. On() { Coffee. Maker. API. api. set. Indicator. State(Coffee. Maker. API. INDICATOR_ON); } public void turn. Off() { Coffee. Maker. API. api. set. Indicator. State(Coffee. Maker. API. INDICATOR_OFF); } } 这种类的存在似乎是只是让代码变得简洁好看一些 从实际作用来看,毫无价值 53
73
- Slides: 73