现代软件工程 - 简单实现


现代软件工程 -简单实现 2011-11-10 1 简单实现 • 主要内容 – 对可见性进行设计 – 将设计映射为代码 – 测试驱动开发和重构 2011-11-10 2 可见性设计 • 对象之间的可见性 – 为了使发送者对象能够向接收者对象发送消息 ,发送者必须具有接受者的可见性 • 可见性 – 是对象”看到”或者引用其他对象的能力 – 与范围有关 – 四种类型 • 属性可见性-B是A的属性 • 参数可见性-B是A中方法的参数 • 局部可见性-B是A中方法的局部对象(不是参数) • 全局可见性-B具有某种方法的全局可见性 2011-11-10 3 从Register到ProductCatalog的可见性是必须的 : RegisterenterItem (itemID, quantity) : ProductCatalog desc = getProductDesc( itemID ) public void enterItem( itemID, qty ) { ... desc = catalog.getProductDesc(itemID) ... } class Register { ... private ProductCatalog catalog ; ... } 2011-11-10 4 • 对发送消息给接收者对象的发送者对象而言,发送者必须 可见接收者——发送者必须拥有某种类型的接收者对象的 指针或引用。 属性可见性 : RegisterenterItem (itemID, quantity) : ProductCatalog desc = getProductDesc( itemID ) public void enterItem(itemID, qty) { ... desc = catalog.getProductDesc(itemID) ... } class Register { ... private ProductCatalog catalog; ... } 2011-11-10 5 • 当B是A的一个属性时,从A到B的属性可见性就存在了. 这是 相对持久的可见性,因为只要A和B存在它就存在了. 参数可见性 • 当B作为一个参数被传递给A的一个方法时,从A到B的参数 可见性就存在了. 这是一个相对暂时的可见性. 2: makeLineItem (desc, qty)enterItem(id, qty) 1: desc = getProductDesc (id) 2.1: create(desc, qty) :Register :Sale :Product Catalog sl : SalesLineItemmakeLineItem (ProductDescription desc , int qty) { ... sl = new SalesLineItem (desc, qty); ... } 在makeLineItem方法的作用域内, Sale拥有 ProductDescription的参数可见性。 属性可见性的参数 2: makeLineItem(desc, qty)enterItem(id, qty) 2: desc = getProductDesc(id) 2.1: create(desc, qty) :Register :Sale :Product Catalog sl : SalesLineItem // initializing method (e.g., a Java constructor) SalesLineItem(ProductDescription desc , int qty) { ... description = desc; // parameter to attribute visibility ... } 2011-11-10 7 • 将参数可见性转化为属性可见性是常见的做法。 局部可见性 • 当B被声明为A的一个方法内的一个局部对象,从A 到B的局部可见性就存在了. 这是一个相对临时的 可见性,因为它仅存在方法的作用域内. • 实现局部可见性的两种常见方式是: •(1)创建一个新的局部实例并赋给一个局部变量; •(2)将一个方法调用返回的对象赋给一个局部变量. 局部可见性 : RegisterenterItem (itemID, quantity) : ProductCatalog desc = getProductDesc( itemID ) enterItem(id, qty) { ... // local visibility via assignment of returning object ProductDescription desc= catalog.getProductDes(id); ... } 2011-11-10 9 将设计映射为代码 • 将设计映射为代码 – 类和接口的定义 – 方法的定义 • 由 DCD创建类的定义 –DCD描述了类或接口的名称、超类、操作的特 征标记以及类的属性,可以从类图直接生成类 的定义 • 从交互图创建方法 – 交互图中的一系列消息可以转化为方法定义中 的一系列语句 2011-11-10 10 Java中的SaleLineItem 2011-11-10 11 SalesLineItem quantity : Integer getSubtotal() : Money ProductDescription description : Text price : Money itemID : ItemID ... Described-by public class SalesLineItem { private int quantity; private ProductDescription productSpec; public SalesLineItem(ProductDescription spec, int qty) {... } public Money getSubtotal() { ... } } * 1 简单属性 引用属性 • 如果在类图中表示了角色名称,可以用它作为代码生 成过程中引用属性名称的基础。 SalesLineItem quantity : Integer getSubtotal() : Money ProductDescription description : Text price : Money itemID : ItemID ... Described-by public class SalesLineItem { ... private int quantity; private ProductDescription productSpec; } productSpec 用在属性名中的角色名 * 1 enterItem交互图 2: makeLineItem (desc, qty)enterItem(id, qty) 1: desc = getProductDesc (id) 2.1: create(desc, qty) 1.1: desc = get(id) :Register :Sale :Product Catalog sl: SalesLineItem lineItems : List: Map 2.2: add(sl) 2011-11-10 13 Register类 ProductCatalog ... getProductDesc(...) Sale isComplete : Boolean time : DateTime becomeComplete() makeLineItem(...) makePayment(...) getTotal() Register ... endSale() enterItem(id: ItemID, qty : Integer) makeNewSale() makePayment(cashTendered : Money) public class Register { private ProductCatalog catalog; private Sale currentSale; public Register(ProductCatalog pc) {...} public void endSale() {...} public void enterItem(ItemID id, int qty) {...} public void makeNewSale() {...} public void makePayment(Money cashTendered) {...} } 1 1 catalog currentSale 2011-11-10 14 enterItem方法 2: makeLineItem(desc, qty)enterItem(id, qty) 1: desc := getProductDescription(id) :Register :Sale :Product Catalog { ProductDescription desc= catalog.ProductDescription(id); currentSale.makeLineItem(desc, qty); } 2011-11-10 15 方法内的每一条在交互图中表示的有序消息都可以被映射成Java方法中的一个语 句。 代码中的集合类 SalesLineItem quantity : Integer getSubtotal() 1..* Sale isComplete : Boolean time : DateTime becomeComplete() makeLineItem() makePayment() getTtotal() public class Sale { ... private List lineItems= new ArrayList(); } A collection class is necessary to maintain attribute visibility to all the SalesLineItems. lineItems 2011-11-10 16 • 一个对象维护一组对其他对象的可见性。 • 多重性为1的一端的类定义了一个指向容器/集合实例的引用 属性,它包含了多重性为多的一端的类的实例。 定义Sale.makeLineItem方法 { lineItems.add( new SalesLineItem (desc, qty) ); } 2: makeLineItem (desc, qty)enterItem(id, qty) 2.1: create(desc, qty) :Register :Sale sl: SalesLineItemlineItems : List 2.2: add(sl) 2011-11-10 17 实现和测试类的可能顺序 SalesLineItem quantity : Integer getSubtotal() ProductCatalog ... getProductDesc(...) ProductDescription description : Text price : Money itemID : ItemID ... Store address : Address name : Text addSale(...) Payment amount : Money ... 1..* 1..* Register ... endSale() enterItem(...) makeNewSale() makePayment(...) Sale isComplete: Boolean time : DateTime becomeComplete() makeLineItem(...) makePayment(...) getTotal() ... 1 1 1 1 1 1 * 1 23 4 56 7 2011-11-10 18 • 从最低耦合到最高耦合,类都需要被实现。 测试驱动开发和重构 • 测试驱动开发(TDD) – 是迭代和敏捷XP方法提倡的优秀实践 – 首先编写测试,然后编写预计要测试的代码 • 优点 – 能够保证编写单元测试 – 使程序员获得满足感从而更始终如一地坚持编 写测试 – 有助于澄清接口和行为的细节 – 可证明、可再现、自动的验证 – 改变事物的信息 2011-11-10 19 测试驱动开发和重构 • 重构 – 是重写和重新构建已有代码的结构化和规律性 方法,但不会改变已有代码的外在行为,而是 采用一系列少量转换的步骤,并且每一步都结 合了重新执行的测试 – 重构的本质是一次实行一小步保留行为的转换 – 每次重构都是小量的 – 目标 • 去除冗余代码 • 改变清晰度 • 使过长的方法变的较短 • 去除硬编码字面常量 2011-11-10 20 测试驱动开发和重构 • 重构 – 坏味代码 • 冗余的代码 • 大型方法 • 具有大量代码的类 • 明显相似的子类 • 在设计中很少使用或没有使用接口 • 许多对象之间有很多的耦合度 • 包含大量其他的垃圾代码 2011-11-10 21 重构样例 重构 描述 提炼方法(Extract Method) 将较长的方法转换为较短的方法,其中将原 有方法中的部分内容分解外私有的帮助者方 法(helper method) 提炼常量( Extract Constant ) 使用常量变量(constant variable)替换字 面常量 引入解释变量(提炼局 部变量的特化) 将表达式的部分或完整结果置入临时变量, 该变量的名字应该能购说明其目的 使用工厂方法代替构造 器调用 例如在Java中调用创建对象的帮助者方法( helper method)来代替对新操作和构造器的 调用(隐藏细节) 2011-11-10 22 重构之前的takeTurn方法 public class Player { private Piece piece; private Board board; private Die[] dice; // … public void takeTurn() { // roll dice int rollTotal = 0; for (int i = 0; i < dice.length; i++) { dice[i].roll(); rollTotal += dice[i].getFaceValue(); } Square newLoc = board.getSquare(piece.getLocation(), rollTotal); piece.setLocation(newLoc); } } // end of class 2011-11-10 23 提炼方法重构之后的代码 public class Player { private Piece piece; private Board board; private Die[] dice; // … public void takeTurn() { // the refactored helper method int rollTotal = rollDice(); Square newLoc = board.getSquare(piece.getLocation(), rollTotal); piece.setLocation(newLoc); } private int rollDice() { int rollTotal = 0; for (int i = 0; i < dice.length; i++) { dice[i].roll(); rollTotal += dice[i].getFaceValue(); } return rollTotal; } } // end of class 2011-11-10 24 引入解释变量之前 // good method name, but the logic of the body is not clear boolean isLeapYear( int year ) { return ( ( ( year % 400 ) == 0 ) || ( ( ( year % 4 ) == 0 ) && ( ( year % 100 ) != 0 ) ) ); } 2011-11-10 25 引入变量之后 // that’s better! boolean isLeapYear( int year ) { boolean isFourthYear = ( ( year % 4 ) == 0 ); boolean isHundrethYear = ( ( year % 100 ) == 0); boolean is4HundrethYear = ( ( year % 400 ) == 0); return ( is4HundrethYear || ( isFourthYear && ! isHundrethYear ) ); } 2011-11-10 26
还剩25页未读

继续阅读

下载pdf到电脑,查找使用更方便

pdf的实际排版效果,会与网站的显示效果略有不同!!

需要 8 金币 [ 分享pdf获得金币 ] 0 人已下载

下载pdf

pdf贡献者

justsoso12

贡献于2012-04-23

下载需要 8 金币 [金币充值 ]
亲,您也可以通过 分享原创pdf 来获得金币奖励!
下载pdf