第五章.良好的设计

聚合(aggregation):聚合是关联的一种特殊形式,表示一件事物是由另一件事物(部分地)组成。

在Java中的称呼:抽象类(abstract class),关系(relationship),继承(inheritance),聚合(aggregation)

在UML中的称呼:抽象类(abstract class),关联(association),泛化(generalization),聚合(aggregation)

OO原则:

1.将变化之物封装起来

2.对接口编码,而不是对实现

3.应用程序中的每一个类只有一个改变的理由

灵活性(flexible),复原力(resilient),耦合度(coupling),内聚力(cohesion)

大多数的好设计都是通过分析坏设计而来的。

不要害怕犯错和改变。

还记得吉他店老板吗(可以看第一章和第二章)?他用我们做的吉他搜索工具,吉他大卖。但是,现在他有了新的需求:

店长说我不想只买吉他,我想增加更多的乐器种类:比如像曼陀林(mandolin)等

回看我们的代码,

项目架构:

Builder.java:

 1 package com.headfirst.guitar;
 2 
 3 public enum Builder {
 4     
 5     FENDER, MARTIN, GIBSON, COLLINGS, OLSON, RYAN, PRS, ANY;
 6     
 7     public String toString(){
 8         switch(this){
 9         case FENDER:
10             return "Fender";
11         case MARTIN:
12             return "Martin";
13         case GIBSON:
14             return "Gibson";
15         case COLLINGS:
16             return "Collings";
17         case OLSON:
18             return "Olson";
19         case RYAN:
20             return "Ryan";
21         case PRS:
22             return "Prs";
23         case ANY:
24             return "Any";
25         default: 
26             return "";
27         }
28     }
29 }
View Code

Type.java:

 1 package com.headfirst.guitar;
 2 
 3 public enum Type {
 4     ACOUSTIC, ELECTRIC;
 5     
 6     public String toString(){
 7         switch(this){
 8         case ACOUSTIC: 
 9             return "acoustic";
10         case ELECTRIC: 
11             return "electric";
12         default:
13             return "";
14         }
15     }
16 }
View Code

Wood.java:

 1 package com.headfirst.guitar;
 2 
 3 public enum Wood {
 4     INDIAN_ROSEWOOD, BRAZILIAN_ROSEWOOD, ALDER;
 5     
 6     public String toString(){
 7         switch(this){
 8         case INDIAN_ROSEWOOD:
 9             return "Indian Rosewood";
10         case BRAZILIAN_ROSEWOOD:
11             return "Brazilian Rosewood";
12         case ALDER:
13             return "Alder";
14         default:
15             return "";
16         }
17     }
18 }
View Code

Guitar.java:

 1 package com.headfirst.guitar;
 2 
 3 public class Guitar {
 4     private String serialNumber;
 5     private double price;
 6     private GuitarSpec guitarSpec;
 7     
 8     public Guitar(String serialNumber, double price, GuitarSpec guitarSpec){
 9         this.serialNumber = serialNumber;
10         this.price = price;
11         this.guitarSpec = guitarSpec;
12     }
13     
14     public String getSerialNumber(){
15         return serialNumber;
16     }
17     public double getPrice(){
18         return price;
19     }
20     public void setPrice(float newPrice){
21         this.price = newPrice;
22     }
23     public GuitarSpec getGuitarSpec(){
24         return guitarSpec;
25     }
26 }
View Code

GuitarSpec.java:

 1 package com.headfirst.guitar;
 2 
 3 public class GuitarSpec {
 4     Builder builder;
 5     String model;
 6     Type type;
 7     Wood backWood;
 8     Wood topWood;
 9     int numStrings;
10     
11     
12     public GuitarSpec(Builder builder, String model, Type type, Wood backWood, Wood topWood){
13         this.builder = builder;
14         this.model = model;
15         this.type = type;
16         this.backWood = backWood;
17         this.topWood = topWood;
18         this.numStrings = numStrings;
19     }
20     
21     public Builder getBuilder(){
22         return this.builder;
23     }
24     
25     public String getModel(){
26         return this.model;
27     }
28     
29     public Type getType(){
30         return this.type;
31     }
32     
33     public Wood getBackWood(){
34         return this.backWood;
35     }
36     
37     public Wood getTopWood(){
38         return this.topWood;
39     }
40     
41     public int getNumStrings(){
42         return this.numStrings;
43     }
44     
45     public boolean matches(GuitarSpec otherSpec){
46         if(builder != otherSpec.builder)
47             return false;
48         if((model != null) && (!model.equals("")) &&
49                 (!model.equalsIgnoreCase(otherSpec.model)))
50             return false;
51         if(type != otherSpec.type)
52             return false;
53         if(numStrings != otherSpec.numStrings)
54             return false;
55         if(backWood != otherSpec.backWood)
56             return false;
57         if(topWood != otherSpec.topWood)
58             return false;
59         
60         return true;
61         }
62 }
View Code

Inventory.java:

 1 package com.headfirst.guitar;
 2 
 3 import java.util.Iterator;
 4 import java.util.LinkedList;
 5 import java.util.List;
 6 
 7 public class Inventory {
 8     
 9     private List guitars;
10     
11     public Inventory(){
12         guitars = new LinkedList();
13     }
14     
15     public void addGuitar(String serialNumber, double price, GuitarSpec guitarSpec){
16         Guitar guitar = new Guitar(serialNumber, price, guitarSpec);
17         guitars.add(guitar);
18     }
19     
20     public Guitar getGuitar(String serialNumber){
21         for(Iterator i = guitars.iterator(); i.hasNext();){
22             Guitar guitar = (Guitar) i.next();
23             if(guitar.getSerialNumber().equals(serialNumber)){
24                 return guitar;
25             }
26         }
27         
28         return null;
29     }
30     
31     public List search(GuitarSpec searchGuitar){
32         List matchingGuitars = new LinkedList();
33         for(Iterator i = guitars.iterator(); i.hasNext();){
34             Guitar guitar = (Guitar) i.next();
35             if(guitar.getGuitarSpec().matches(searchGuitar))
36                 matchingGuitars.add(guitar);
37         }
38         
39         return matchingGuitars;
40     }
41 }
View Code

FindGuitarTester.java:

 1 package com.headfirst.guitar;
 2 
 3 import java.util.Iterator;
 4 import java.util.List;
 5 
 6 public class FindGuitarTester {
 7     public static void main(String[] args){
 8         Inventory inventory = new Inventory();
 9         initializeInventory(inventory);
10         
11         GuitarSpec whatErinLikes = new GuitarSpec(Builder.FENDER, "Stratocastor", Type.ELECTRIC, Wood.ALDER, Wood.ALDER);
12         
13         List matchingGuitars = inventory.search(whatErinLikes);
14         if(!matchingGuitars.isEmpty()){
15             System.out.println("Erin, you might like these guitars: "); 
16             for(Iterator i = matchingGuitars.iterator(); i.hasNext();){
17                 Guitar guitar = (Guitar) i.next();
18                 GuitarSpec guitarSpec = guitar.getGuitarSpec();
19                 System.out.println("We have a " +
20                 guitarSpec.getBuilder() + " " + guitarSpec.getModel() + " " + 
21                 guitarSpec.getType() + " guitar:
 " + 
22                 guitarSpec.getBackWood() + " back and sides,
 " +
23                 guitarSpec.getTopWood() + " top.
You can have it for only $" + 
24                 guitar.getPrice() + "!");
25             }
26         }else{
27             System.out.println("Sorry, Erin, we have nothing for you.");
28         }
29     }
30     
31     private static void initializeInventory(Inventory inventory){
32         GuitarSpec guitarSpec1 = new GuitarSpec(Builder.FENDER, "Stratocastor", Type.ELECTRIC, Wood.ALDER, Wood.ALDER);
33         inventory.addGuitar("V95693", 1499.95, guitarSpec1);
34         inventory.addGuitar("B1234", 1600.35, guitarSpec1);
35     }
36 }
View Code

上面代码,如果有什么疑问,可以指出。

根据吉他店长,不,应该叫乐器店长,的指示。我们来扩展和修改我们上面的代码,看有什么问题?

我们只有一个Guitar类,想要Mandolin类,再创建一个吧。想到两者似乎有些相同的地方,可以我们抽象出Instrument类怎么样,让新增的乐器都继承它。

太棒了!GuitarSpec类也一样,我们抽象出InstrumentSpec类,让新增的乐器属性都继承自它。

这是我们构建出的新的UML类图。

根据上图写代码:

新建项目:

 

你可以像我一样新建一个项目,也可以在原有项目基础上更改。

Builder.java:

 1 package com.headfirst.instrument;
 2 
 3 public enum Builder {
 4 FENDER, MARTIN, GIBSON, COLLINGS, OLSON, RYAN, PRS, ANY;
 5     
 6     public String toString(){
 7         switch(this){
 8         case FENDER:
 9             return "Fender";
10         case MARTIN:
11             return "Martin";
12         case GIBSON:
13             return "Gibson";
14         case COLLINGS:
15             return "Collings";
16         case OLSON:
17             return "Olson";
18         case RYAN:
19             return "Ryan";
20         case PRS:
21             return "Prs";
22         case ANY:
23             return "Any";
24         default: 
25             return "";
26         }
27     }
28 }
View Code

Style.java:

 1 package com.headfirst.instrument;
 2 
 3 public enum Style {
 4     A, F;
 5     
 6     public String toString(){
 7         switch(this){
 8         case A:
 9             return "a";
10         case F:
11             return "F";
12         default:
13             return "kong";
14         }
15     }
16 }
View Code

Type.java:

 1 package com.headfirst.instrument;
 2 
 3 public enum Type {
 4     ACOUSTIC, ELECTRIC;
 5     
 6     public String toString(){
 7         switch(this){
 8         case ACOUSTIC: 
 9             return "acoustic";
10         case ELECTRIC: 
11             return "electric";
12         default:
13             return "";
14         }
15     }
16 }
View Code

Wood.java:

 1 package com.headfirst.instrument;
 2 
 3 public enum Wood {
 4     INDIAN_ROSEWOOD, BRAZILIAN_ROSEWOOD, ALDER;
 5     
 6     public String toString(){
 7         switch(this){
 8         case INDIAN_ROSEWOOD:
 9             return "Indian Rosewood";
10         case BRAZILIAN_ROSEWOOD:
11             return "Brazilian Rosewood";
12         case ALDER:
13             return "Alder";
14         default:
15             return "";
16         }
17     }
18 }
View Code

Instrument.java:

 1 package com.headfirst.instrument;
 2 
 3 public abstract class Instrument {
 4     
 5     private String serialNumber;
 6     private double price;
 7     private InstrumentSpec spec;
 8     
 9     public Instrument(String serialNumber, double price, InstrumentSpec spec){
10         this.serialNumber = serialNumber;
11         this.price = price;
12         this.spec = spec;
13     }
14     
15     public String getSerialNumber(){
16         return serialNumber;
17     }
18     public double getPrice(){
19         return price;
20     }
21     public void setPrice(){
22         this.price = price;
23     }
24     
25     public InstrumentSpec getSpec(){
26         return spec;
27     }
28 }
View Code

InstrumentSpec.java:

 1 package com.headfirst.instrument;
 2 
 3 
 4 public abstract class InstrumentSpec {
 5     
 6     private Builder builder;
 7     private String model;
 8     private Type type;
 9     private Wood backWood;
10     private Wood topWood;
11     
12     public InstrumentSpec(Builder builder, String model, Type type, Wood backWood, Wood topWood){
13         this.builder = builder;
14         this.model = model;
15         this.type = type;
16         this.backWood = backWood;
17         this.topWood = topWood;
18     }
19     
20     public Builder getBuilder(){
21         return this.builder;
22     }
23     
24     public String getModel(){
25         return this.model;
26     }
27     
28     public Type getType(){
29         return this.type;
30     }
31     
32     public Wood getBackWood(){
33         return this.backWood;
34     }
35     
36     public Wood getTopWood(){
37         return this.topWood;
38     }
39     
40     public boolean matches(InstrumentSpec otherSpec){
41         if(builder != otherSpec.builder)
42             return false;
43         if((model != null) && (!model.equals("")) && (!model.equalsIgnoreCase(otherSpec.model)))
44             return false;
45         if(type != otherSpec.type)
46             return false;
47         if(backWood != otherSpec.backWood)
48             return false;
49         if(topWood != otherSpec.topWood)
50             return false;
51         
52         return true;
53     }
54 }
View Code

Guitar.java:

1 package com.headfirst.instrument;
2 
3 public class Guitar extends Instrument {
4     
5     public Guitar(String serialNumber, double price, GuitarSpec spec){
6         super(serialNumber, price, spec);    
7     }
8 }
View Code

GuitarSpec.java:

 1 package com.headfirst.instrument;
 2 
 3 public class GuitarSpec extends InstrumentSpec {
 4     private int numStrings;//Guitar自身属性
 5     
 6     public GuitarSpec(Builder builder, String model, Type type, Wood backWood, Wood topWood, int numStrings){
 7         super(builder, model, type, backWood, topWood);
 8         
 9         this.numStrings = numStrings;
10     }
11     
12     public int getNumStrings(){
13         return numStrings;
14     }
15     
16     //Override the superclass matches()
17     public boolean matches(InstrumentSpec otherSpec){
18         if(!super.matches(otherSpec)){
19             return false;    
20         }
21         if(!(otherSpec instanceof GuitarSpec))
22             return false;
23         GuitarSpec spec = (GuitarSpec) otherSpec;
24         if( numStrings != spec.numStrings)
25             return false;
26         
27         return true;
28     }
29 }
View Code

Mandolin.java:

1 package com.headfirst.instrument;
2 
3 public class Mandolin extends Instrument {
4     
5     public Mandolin(String serialNumber, double price, MandolinSpec spec){
6         super(serialNumber, price, spec);
7     }
8 }
View Code

MandolinSpec.java:

 1 package com.headfirst.instrument;
 2 
 3 public class MandolinSpec extends InstrumentSpec {
 4     private Style style;
 5     
 6     public MandolinSpec(Builder builder, String model, Type type, Wood backWood, Wood topWood, Style style){
 7         super(builder, model, type, backWood, topWood);
 8         
 9         this.style = style;
10     }
11     
12     public Style getStyle(){
13         return style;
14     }
15     //Override the superclass matches()
16     public boolean matches(InstrumentSpec otherSpec){
17         if(!(super.matches(otherSpec)))
18             return false;
19         if(!(otherSpec instanceof MandolinSpec))
20             return false;
21         MandolinSpec spec = (MandolinSpec) otherSpec;
22         if(!style.equals(spec.style))
23             return false;
24         
25         return true;
26     }
27 }
View Code

Inventory.java:

 1 package com.headfirst.instrument;
 2 
 3 import java.util.Iterator;
 4 import java.util.LinkedList;
 5 import java.util.List;
 6 
 7 public class Inventory {
 8     
 9     private List inventory;
10     
11     public Inventory(){
12         inventory = new LinkedList();
13     }
14     
15     public void addInstrument(String serialNumber, double price, InstrumentSpec spec){
16         Instrument instrument = null;
17         if(spec instanceof GuitarSpec){
18             instrument = new Guitar(serialNumber, price, (GuitarSpec) spec);
19         }else if(spec instanceof MandolinSpec){
20             instrument = new Mandolin(serialNumber, price, (MandolinSpec) spec);
21         }
22         
23         inventory.add(instrument);
24     }
25     
26     public Instrument get(String serialNumber){
27         for(Iterator i = inventory.iterator(); i.hasNext();){
28             Instrument instrument = (Instrument) i.next();
29             if(instrument.getSerialNumber().equals(serialNumber)){
30                 return instrument;
31             }
32         }
33         
34         return null;
35     }
36     
37     public List search(GuitarSpec searchSpec){
38         List matchingGuitars = new LinkedList();
39         for(Iterator i = inventory.iterator(); i.hasNext();){
40             Guitar guitar = (Guitar) i.next();
41             if(guitar.getSpec().matches(searchSpec))
42                 matchingGuitars.add(guitar);
43         }
44         
45         return matchingGuitars;
46     }
47     
48     public List search(MandolinSpec searchSpec){
49         List matchingMandolins = new LinkedList();
50         for(Iterator i = inventory.iterator(); i.hasNext();){
51             Mandolin mandolin = (Mandolin) i.next();
52             if(mandolin.getSpec().matches(searchSpec))
53                 matchingMandolins.add(mandolin);
54         }
55         
56         return matchingMandolins;
57     }
58 }
View Code

没有写FindInstrumentTester.java,因为这个项目有个问题,很难扩展。

不信?我说,你来修改一下,现在我们要增加乐器:古筝,短笛,箫,二胡......;一共一百种,而且每种乐器带有自身的特殊属性,不多每种就带一种吧。

是不是代码写到你手酸?不是,好吧,那你一定为你的复制粘贴而沾沾自喜。

下面我们对上面Instrument项目进行修改,怎样在增加很多乐器的时候,我们的代码改动性很小。

来说几个OO原则:

1.接口(interface):对接口编程,而不是对实现编程,软件更容易被扩展。通过接口编程,程序代码将使用该接口的所有子类,甚至是没被创建的那些。

2.封装(encapsulation):将变化之物封装起来,将不变之物也封装起来。通过封装你改动的代码将在封装之内,对于封装之外的代码,你不必担心。

3.变更(change):每个类只有一个改变的理由。减少引起该类变动的因素,就可以让此类发生变动的机会最小化。每个类只做一件事。

说一说,项目扩展的难处在哪里吧:

首先,要通过继承Instrument类,写出很多实现乐器类,通过继承InstrumentSpec类,写出很多实现乐器属性类

其次,乐器有不同的特殊属性,要在乐器属性类中添加上,在对比matches方法中也要对比这些特殊属性

最后,在Inventory类中,search方法要根据多少种乐器,写出多少种搜索方法

这些问题所在,就是我们继承了Instrument抽象类和InstrumentSpec抽象类,因为抽象类不能实例化,导致有多少乐器就要写多少。

有没有办法,把所有的乐器都用一个Instrument类表示?这样我们就不用写太多的子类了,我们只在乐器属性中中添加一个instrumentType变量来存储乐器的种类

如果这样,那些乐器特有的属性怎样表示?不可能所有乐器的属性都相同吧。

有没有想过封装,我们把乐器的属性在进一步封装起来,但我们不把属性封装到类中,而是封装在Map中,一个属性一个键值对。InstrumentSpec中存储Map。想要哪个属性就去里面取值就好了。

搜索方法写太多,没关系,我们也把InstrumentSpec也只用一个表示,怎么样?

说了这么多,具体怎么实现,是还不明白。那么就让我执笔敲出上述代码:

项目架构:

 

枚举多了一个InstrumentType,用来存储乐器种类,其余的枚举有的里面增加了一些内容:

Builder.java:

 1 package com.headfirst.instrumentfinalversion;
 2 
 3 public enum Builder {
 4 FENDER, MARTIN, GIBSON, COLLINGS, OLSON, RYAN, PRS, ANY;
 5     
 6     public String toString(){
 7         switch(this){
 8         case FENDER:
 9             return "Fender";
10         case MARTIN:
11             return "Martin";
12         case GIBSON:
13             return "Gibson";
14         case COLLINGS:
15             return "Collings";
16         case OLSON:
17             return "Olson";
18         case RYAN:
19             return "Ryan";
20         case PRS:
21             return "Prs";
22         case ANY:
23             return "Any";
24         default: 
25             return "";
26         }
27     }
28 }
View Code

InstrumentType.java:

 1 package com.headfirst.instrumentfinalversion;
 2 
 3 public enum InstrumentType {
 4     GUITAR, BANJO, DOBRO, FIDDLE, BASS, MANDOLIN;
 5     
 6     public String toString(){
 7         switch(this){
 8         case GUITAR:
 9             return "Guitar";
10         case BANJO:
11             return "Banjo";
12         case DOBRO:
13             return "Dobro";
14         case FIDDLE:
15             return "Fiddle";
16         case BASS:
17             return "Bass";
18         case MANDOLIN:
19             return "Mandolin";
20         default:
21             return "Unspecified";
22         }
23     }
24 }
View Code

Style.java:

 1 package com.headfirst.instrumentfinalversion;
 2 
 3 public enum Style {
 4     A, F;
 5     
 6     public String toString(){
 7         switch(this){
 8         case A:
 9             return "a";
10         case F:
11             return "F";
12         default:
13             return "kong";
14         }
15     }
16 }
View Code

Type.java:

 1 package com.headfirst.instrumentfinalversion;
 2 
 3 public enum Type {
 4     ACOUSTIC, ELECTRIC;
 5     
 6     public String toString(){
 7         switch(this){
 8         case ACOUSTIC: 
 9             return "acoustic";
10         case ELECTRIC: 
11             return "electric";
12         default:
13             return "";
14         }
15     }
16 }
View Code

Wood.java:

 1 package com.headfirst.instrumentfinalversion;
 2 
 3 public enum Wood {
 4     INDIAN_ROSEWOOD, BRAZILIAN_ROSEWOOD, ALDER, MAPLE, SITKA, MAHOGANY, ADIRONDACK;
 5     
 6     public String toString(){
 7         switch(this){
 8         case INDIAN_ROSEWOOD:
 9             return "Indian Rosewood";
10         case BRAZILIAN_ROSEWOOD:
11             return "Brazilian Rosewood";
12         case ALDER:
13             return "Alder";
14         case MAPLE:
15             return "Maple";
16         case SITKA:
17             return "Sitka";
18         case MAHOGANY:
19             return "Mahogany";
20         case ADIRONDACK:
21             return "Adirondack";
22         default:
23             return "";
24         }
25     }
26 }
View Code

 Instrument.java:

 1 package com.headfirst.instrumentfinalversion;
 2 
 3 public class Instrument {
 4     private String serialNumber;
 5     private double price;
 6     private InstrumentSpec spec;
 7     
 8     public Instrument(String serialNumber, double price, InstrumentSpec spec){
 9         this.serialNumber = serialNumber;
10         this.price = price;
11         this.spec = spec;
12     }
13     
14     public String getSerialNumber(){
15         return serialNumber;
16     }
17     
18     public double getPrice(){
19         return price;
20     }
21     
22     public InstrumentSpec getSpec(){
23         return spec;
24     }
25 }
View Code

InstrumentSpec.java:

 1 package com.headfirst.instrumentfinalversion;
 2 
 3 import java.util.HashMap;
 4 import java.util.Iterator;
 5 import java.util.Map;
 6 
 7 public class InstrumentSpec {
 8     private Map properties;
 9     
10     public InstrumentSpec(Map properties){
11         if(properties == null){
12             this.properties = new HashMap();
13         }else{
14             this.properties = new HashMap(properties);
15         }
16     }
17     
18     public Object getProperty(String propertyName){
19         return properties.get(propertyName);
20     }
21     
22     public Map getProperties(){
23         return properties;
24     }
25     
26     public boolean matches(InstrumentSpec otherSpec){
27         for(Iterator i = otherSpec.getProperties().keySet().iterator(); i.hasNext();){
28             String propertyName = (String) i.next();
29             if(!properties.get(propertyName).equals(otherSpec.getProperty(propertyName)))
30                 return false;
31         }
32         
33         return true;
34     }
35 }
View Code

Inventory.java:

 1 package com.headfirst.instrumentfinalversion;
 2 
 3 import java.util.Iterator;
 4 import java.util.LinkedList;
 5 import java.util.List;
 6 
 7 public class Inventory {
 8     private List inventory;
 9     
10     public Inventory(){
11         inventory = new LinkedList();
12     }
13     
14     public void addInstrument(String serialNumber, double price, InstrumentSpec spec){
15         Instrument instrument = new Instrument(serialNumber, price, spec);
16         inventory.add(instrument);
17     }
18     
19     public Instrument get(String serialNumber){
20         for(Iterator i = inventory.iterator(); i.hasNext();){
21             Instrument instrument = (Instrument) i.next();
22             if(instrument.getSerialNumber().equals(serialNumber))
23                 return instrument;
24         }
25         
26         return null;
27     }
28     
29     public List search(InstrumentSpec searchSpec){
30         List matchingInstruments = new LinkedList();
31         for(Iterator i = inventory.iterator(); i.hasNext();){
32             Instrument instrument = (Instrument) i.next();
33             if(instrument.getSpec().matches(searchSpec))
34                 matchingInstruments.add(instrument);
35         }
36         
37         return matchingInstruments;
38     }
39 }
View Code

FindInstrument.java:

 1 package com.headfirst.instrumentfinalversion;
 2 
 3 import java.util.HashMap;
 4 import java.util.Iterator;
 5 import java.util.List;
 6 import java.util.Map;
 7 
 8 public class FindInstrument {
 9     
10     private static void initializeInventory(Inventory inventory){
11         Map properties = new HashMap();
12         properties.put("InstrumentType", InstrumentType.GUITAR);
13         properties.put("builder", Builder.COLLINGS);
14         properties.put("model", "CJ");
15         properties.put("type", Type.ACOUSTIC);
16         properties.put("numStrings", 6);
17         properties.put("topWood", Wood.INDIAN_ROSEWOOD);
18         properties.put("backWood", Wood.SITKA);
19         inventory.addInstrument("11277", 3999.95, new InstrumentSpec(properties));
20         
21         properties.put("builder", Builder.MARTIN);
22         properties.put("model", "D-18");
23         properties.put("topWood", Wood.MAHOGANY);
24         properties.put("backWood", Wood.ADIRONDACK);
25         inventory.addInstrument("122784", 5495.95, new InstrumentSpec(properties));
26         
27         properties.put("builder", Builder.FENDER);
28         properties.put("model", "Stratocastor");
29         properties.put("type", Type.ELECTRIC);
30         properties.put("topWood", Wood.ALDER);
31         properties.put("backWood", Wood.ALDER);
32         inventory.addInstrument("V9512", 1549.95, new InstrumentSpec(properties));
33         
34         properties.put("builder", Builder.GIBSON);
35         properties.put("model", "Les Paul");
36         properties.put("topWood", Wood.MAPLE);
37         properties.put("backWood", Wood.MAPLE);
38         inventory.addInstrument("70108276", 2295.95, new InstrumentSpec(properties));
39         
40         properties.put("model", "SG '61 Reissue");
41         properties.put("topWood", Wood.MAHOGANY);
42         properties.put("backWood", Wood.MAHOGANY);
43         inventory.addInstrument("82765501", 1890.95, new InstrumentSpec(properties));
44         
45         properties.put("InstrumentType", InstrumentType.MANDOLIN);
46         properties.put("model", "F-5G");
47         properties.put("type", Type.ACOUSTIC);
48         properties.remove("numStrings");//假如使用相同的properties Map,别忘了为Mandolin移除numStrings
49         properties.put("topWood", Wood.MAPLE);
50         properties.put("backWood", Wood.MAPLE);
51         inventory.addInstrument("9019920", 5495.95, new InstrumentSpec(properties));
52         
53         properties.put("InstrumentType", InstrumentType.BANJO);
54         properties.put("model", "RB-3 Wreath");
55         properties.put("type", Type.ACOUSTIC);
56         properties.remove("topWood");
57         properties.put("numStrings", 5);
58         inventory.addInstrument("8900231", 2945.95, new InstrumentSpec(properties));
59     }
60     
61     public static void main(String[] args){
62         //Set up Rick's inventory
63         Inventory inventory = new Inventory();
64         initializeInventory(inventory);
65         
66         Map properties = new HashMap();
67         properties.put("builder", Builder.GIBSON);
68         properties.put("backWood", Wood.MAPLE);
69         InstrumentSpec clientSpec = new InstrumentSpec(properties);
70         
71         List matchingInstruments = inventory.search(clientSpec);
72         if(!matchingInstruments.isEmpty()){
73             System.out.println("You might like these instruments:");
74             for(Iterator i = matchingInstruments.iterator(); i.hasNext();){
75                 Instrument instrument = (Instrument)i.next();
76                 InstrumentSpec spec = instrument.getSpec();
77                 System.out.println("We have a " + spec.getProperty("instrumentType") + " with the following properties:");
78                 for(Iterator j = spec.getProperties().keySet().iterator(); j.hasNext();){
79                     String propertyName = (String)j.next();
80                     if(propertyName.equals("instrumentType"))
81                         continue;
82                     System.out.println("   " + propertyName + ": " + spec.getProperty(propertyName));
83                 }
84                 System.out.println(" You can have this " + spec.getProperty("instrumentType") + " for $" + instrument.getPrice() + "
---");
85                 
86             }
87         }else{
88             System.out.println("Sorry, we have nothing for you .");
89         }
90     }
91     
92     
93 }
View Code

上面的代码好好看一下,很值得品味,现在我的水平认为这是一段我从没有想过的,真是简单可行。

运行结果:

好的知识,分享给大家。

参考网址:

equalsIgnoreCase():http://blog.csdn.net/yujian_bing/article/details/8171379

Iterator keySet():https://zhidao.baidu.com/question/1303782909568685779.html

同一个Map键值对覆盖问题:http://blog.csdn.net/wide288/article/details/72828000

这一章很重要,学会思路,而不是学会敲代码!

原文地址:https://www.cnblogs.com/lanshanxiao/p/7197905.html