2016年7月2日 星期六

[OO 設計模式] Gossip@DesignPattern : Behavioral - Visitor 模式

轉載自 這裡 
您的系統中有 客戶會員 與 VIP,假設經過設計考量,確定以下的設計是必要的 : 
  1. class Customer {  
  2.     void doCustomer() {  
  3.         System.out.println("客戶服務");  
  4.     }  
  5.     void pay() {  
  6.         System.out.println("結帳");  
  7.     }  
  8. }  
  9.   
  10. class Member extends Customer {  
  11.     void doMember() {  
  12.         System.out.println("會員服務");  
  13.     }  
  14. }  
  15.       
  16. class VIP extends Customer {  
  17.     void doVIP() {  
  18.         System.out.println("VIP 服務");  
  19.     }  
  20. }  
您要設計一個結帳功能,針對客戶所使用的服務計算客戶要付的費用,計算的演算大部份是針對 Customer 來進行操作,但其中幾個步驟,不免要針對特定客戶類型來設計,例如 : 
  1. class Service {  
  2.     void doService(Customer customer) {  
  3.         customer.doCustomer();  
  4.         if(customer instanceof Member) {  
  5.             ((Member) customer).doMember();  
  6.         }  
  7.         if(customer instanceof VIP) {  
  8.             ((VIP) customer).doVIP();  
  9.         }  
  10.         customer.pay();  
  11.     }  
  12. }  
使用 instanceof 來判斷物件類型,一般是不被鼓勵的,如果您的客戶類型繁多,這樣的結構化設計會逐漸加深程式碼的繁複。一般多希望利用多型操作來解決問題,不要針對特定類型來進行設計. 如果經過仔細的考量設計,必須針對特定類型來進行操作確實是不可避免的,那麼您可以換個方式,例如 : 
  1. interface Visitable {  
  2.     void accept(Visitor visitor);  
  3. }  
  4.   
  5. interface Visitor {  
  6.     void visit(Member member);  
  7.     void visit(VIP vip);  
  8. }  
  9.   
  10. class Customer implements Visitable {  
  11.     void doCustomer() {  
  12.         System.out.println("客戶服務");  
  13.     }  
  14.     void pay() {  
  15.         System.out.println("結帳");  
  16.     }  
  17.     public void accept(Visitor visitor) {  
  18.         // nothing to do  
  19.     }      
  20. }  
  21.   
  22. class Member extends Customer {  
  23.     void doMember() {  
  24.         System.out.println("會員服務");  
  25.     }  
  26.     @Override  
  27.     public void accept(Visitor visitor) {  
  28.         visitor.visit(this); // 看似多型,其實是 overload  
  29.     }      
  30. }  
  31.       
  32. class VIP extends Customer {  
  33.     void doVIP() {  
  34.         System.out.println("VIP 服務");  
  35.     }  
  36.     @Override  
  37.     public void accept(Visitor visitor) {  
  38.         visitor.visit(this); // 看似多型,其實是 overload  
  39.     }      
  40. }  
  41.   
  42. class VisitorImpl implements Visitor {  
  43.     public void visit(Member member) {  
  44.         member.doMember();  
  45.     }  
  46.     public void visit(VIP vip) {  
  47.         vip.doVIP();  
  48.     }  
  49. }  
  50.   
  51. class Service {  
  52.     private Visitor visitor = new VisitorImpl();  
  53.     void doService(Customer customer) {  
  54.         customer.doCustomer();  
  55.         ((Visitable) customer).accept(visitor);  
  56.         customer.pay();  
  57.     }  
  58. }  
  59.   
  60. public class Main {  
  61.     public static void main(String[] args) {  
  62.         Service service = new Service();  
  63.         service.doService(new Member());  
  64.     }  
  65. }  
doService() 方法接受的是 Customer 型態,原先為了針對特別型態作特定操作,不得已使用 instanceof 作判斷,而上面這個設計,則是 Visitor 登門入戶,使用物件中的 this 參考名稱之型態資訊,由物件自行選擇要呼叫的overload方法
這是Visitor模式的一個實現,Visitor 模式的目的,是將演算流程與所操作的物件之特定結構分離,這樣分離之後,針對特定物件的操作部份將集中在 Visitor 中管理,並可以隨時修改操作

Visitor 模式的 UML 結構類圖如下 : 

[Scala IA] The Basics : Ch2. Getting Started - Controlling flow with loops, ifs and For-comprehensio

Controlling flow with loops and ifs 
It’s a little hard to get into useful programming or scripting with Scala without the loops and ifs. Well, your wait is over. In Scala, if and else blocks work as they do in any other programming language. If the expression inside the ifevaluates to true, then the if block gets executed; otherwise, the else block is executed. The interesting part about Scala is that every statement is an expression, and its value is determined by the last expression within the statement. Assigning a value depending on some condition in Scala could look like this: 
  1. val someValue = if(some condition) value1 else value2  
For example: 
scala> val useDefault = false
useDefault: Boolean = false

scala> val configFile = if(useDefault) "default.txt" else "custom.txt"
configFile: String = custom.txt

Scala doesn’t support the ? operator as Java does, but I don’t think you’ll miss it in Scala. You can nest if/else blocks, and you can combine multiple if/else blocks using else if. Loops in Scala have all the usual suspects like the while loop and do-while, but the most interesting looping construct is for or for-comprehensions. The while and do-while loops are pretty standard, and in Scala they aren’t any different from Java or C#. The next section looks at Scala for-comprehensions. 

For-comprehensions 
A for-comprehension in Scala is like a Swiss Army knife: you can do many things with it using basic simple elements. The for expression in Scala consists of a for keyword followed by one or more enumerators surrounded by parentheses and followed by an expression block or yield expression (see figure 2.2). 
 

Before I go into yield expression, let’s look into the more traditional form of the for loop. The common pattern used in a for loop is to iterate through a collection. To print all the files in a directory that end with the .scala extension, for example, you have to do something like the following: 
  1. val files = new java.io.File(".").listFiles  
  2. for(file <- files="" nbsp="" span="">
  3.     val filename = file.getName  
  4.     if(fileName.endsWith(".scala")) println(file)  
  5. }  

The only thing that looks different from for loops in Java or C# is the expression file <- files="" font="">. In Scala this is called a generator, and the job of a generator is to iterate through a collection. The right side of the <- b=""> represents the collection—in this case, files. For each element in the collection (file in this case) it executes the for block. This is similar to the way you define a for loop in Java: 

  1. for(File file: files) {  
  2.     String filename = file.getName();  
  3.     if(filename.endsWith(".scala")) System.out.println(file);  
  4. }  
In the case of Scala, you don’t have to specify the type of file object because Scala type inference will take care of it. Apart from the generator, you can use other ingredients in a Scala for loop to simplify the previous example. 
  1. for(  
  2.     file <- files="" nbsp="" span="">
  3.     fileName = file.getName;  
  4.     if(fileName.endsWith(".scala"))  
  5. ) println(file)  
Scala for loops allow you to specify definitions and guard clauses inside the loop. In this case you’re defining a filename variable and checking whether the filename ends with .scala. The loop will execute when the given guard clause is true, so you’ll get the same result as the previous example. Note that all the variables created inside a for expression are of the val type, so they can’t be modified and hence reduce the possibility of side effects. 

As mentioned earlier, it’s possible to specify more than one generator in a Scala for loop control. The following example executes the loop for each generator and adds them: 
scala> val aList = List(1, 2, 3)
aList: List[Int] = List(1, 2, 3)

scala> val bList = List(4, 5, 6, 7)
bList: List[Int] = List(4, 5, 6, 7)

scala> for {a <- a="" alist="" b="" blist="" font="" println="">
5
6
7
8
6
7
8
9
7
8
9
10

The generators in this case are aList and bList, and when you have multiple generators, each generator is repeated for the other generator. When a = 1 for each value of b, that is, b = 4, b = 5, b = 6, the loop will be executed, and so on. I used curly braces to surround the for expression, but you don’t have to; you could use (). I tend to use curly braces when I have more than one generator and guard clause. 

The for-comprehension in Scala comes in two flavors. You’ve already seen one form in the previous examples: the imperative form. In this form you specify the statements that will get executed by the loop, and it doesn’t return anything. The other form of for-comprehension is called the functional form (sometimes it’s also called sequence comprehension). In the functional form, you tend to work with values rather than execute statements, and it does return a value. Look at the same example in functional form: 
scala> for {a <- a="" alist="" b="" blist="" font="" yield="">
res4: List[Int] = List(5, 6, 7, 8, 6, 7, 8, 9, 7, 8, 9, 10)

Instead of printing the value of a + b, you’re returning the value of the addition from the loop using the yield keyword. You’re using the same aList and bList instances in the loop control, and it returns the result as a List. Now if you want to print the result, as in the previous example, you have to loop through the result List
scala> val result = for {a <- a="" alist="" b="" blist="" font="" yield="">
result: List[Int] = List(5, 6, 7, 8, 6, 7, 8, 9, 7, 8, 9, 10) 
scala> for(r <- font="" println="" r="" result="">
5
6
7
8
6
7
8
9
7
8
9
10
It does look like the functional form is more verbose than the imperative form, but think about it. You’ve separated the computation (the adding of two numbersfrom how you’re using it—in this case, printing the result. This improves the reusability and compatibility of functions or computations, which is one of the benefits of functional programming. In the following example you reuse the result produced by the for yield loop to create an XML node: 
scala> val xmlNode = {result.mkString(",")}
xmlNode: scala.xml.Elem = 5,6,7,8,6,7,8,9,7,8,9,10

The mkString is a method defined in scala.collection.immutable.List. It takes each element in the List and concatenates each element with whatever separator you provide—in this case, a comma. Even though it doesn’t make sense, what if you try to print inside the yield expression? What will happen? Remember, everything in Scala is an expression and has a return value. If you try the following, you’ll still get a result, but the result won’t be useful because it will be a collection of units. A unit is the equivalent of void in Java, and it’s the result value of a println function used inside the yield expression: 
scala> for { a<- a="" alist="" b="" blist="" font="" println="" yield="">
...
res6: List[Unit] = List((), (), (), (), (), (), (), (), (), (), (), ())

You’ve only scratched the surface of for-comprehension, and I come back to this in chapter 4 to examine functional data structures, so hold on to your inquisitiveness until chapter 4 (or jump to that chapter). The next section moves into another functional concept: pattern matching.

[Git 常見問題] error: The following untracked working tree files would be overwritten by merge

  Source From  Here 方案1: // x -----删除忽略文件已经对 git 来说不识别的文件 // d -----删除未被添加到 git 的路径中的文件 // f -----强制运行 #   git clean -d -fx 方案2: 今天在服务器上  gi...