大話設計模式-----(三)工廠方法模式、原型模式、模板方法模式
工廠方法模式
簡單工廠模式是恩,按那個計算器來寫的話,就是把運算子都具有的特性抽象出來作為父類。然後想新增運算型別,只需要對應的增加繼承其運算子抽象類,然後新增自己的運算方法即可。但是要在工廠類中修改switch 增加判斷。
對應的工廠方法模式就是把工廠類這個類也抽象出來。對每個運算子子類都建立一個對應的工廠來建立。所有小工廠繼承工廠抽象類。
這樣增加運算的話只需在繼承實現運算子,在繼承實現對應的小工廠類。然後在客戶端中就使用什麼類就建立哪個小工廠即可。利用小工廠來建立小運算類。
工廠也抽象出來定義個介面
interface IFactory{
//每個工廠都有的方法返回自己這個小工廠建立的運算子類利用多型返回
Operation Createoperation();
}
//
class AddFactory implements IFactory{
@Override
public Operation Createoperation() {
return new OperationAdd();//返回對應運算子的子類
}
}
class SubFactory implements IFactory{
@Override
public Operation Createoperation() {
return OperationSub();
}
}
客戶端
public static void main(String[] args) {
//對應的位元組new 加法的工廠,用父類接著,然後呼叫其工廠的建立運算子的方法建立。用運算子抽象類接著。設定其屬性,呼叫其方法。
IFactory iFactory = new AddFactory();
Operation operation = iFactory.Createoperation();
operation.setNumberA(2);
operation.setNumberB(3);
operation.getResult();
}
簡單工廠模式的最大優點在於工廠類中包含了必要的邏輯判斷,根據客戶端的選擇條件動態例項化相關的類,對於客戶端磊說,去除了與具體產品的依賴。
工廠方法使一個類的例項化延遲到其子類
工廠方法模式克服了簡單工廠模式違背開放封閉原則的缺點,又保持了封裝物件建立過程的優點。使用了多型性。
本來修改的是工廠類。現在修改的是客戶端
原型模式
原型模式其實就是從一個物件再建立另外一個可定製的物件。而且不需要知道任何建立的細節。
//利用java 的Cloneable介面來定義原型類
class ConcretePrototype implements Cloneable{
ConcretePrototype concretePrototype;
private String nameString;
public String getNameString() {
return nameString;
}
public void setNameString(String nameString) {
this.nameString = nameString;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
private int age;
//定義克隆方法
public ConcretePrototype clone() {
try {
concretePrototype= (ConcretePrototype) super.clone();
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return concretePrototype;
}
}
客戶端
public static void main(String[] args) {
ConcretePrototype concretePrototype1 = new ConcretePrototype();
concretePrototype1.setNameString("one");
concretePrototype1.setAge(18);
ConcretePrototype concretePrototype2,concretePrototype3;
concretePrototype2 = concretePrototype1.clone();
concretePrototype3 = concretePrototype1.clone();
concretePrototype2.setNameString("two");
concretePrototype2.setAge(19);
concretePrototype3.setNameString("three");
concretePrototype3.setAge(20);
System.out.println("one:"+concretePrototype1.getNameString());
System.out.println("two:"+concretePrototype2.getNameString());
System.out.println("three:"+concretePrototype3.getNameString());
}
clone是淺複製。如果是物件的話就不能複製了。物件只能複製其引用,就是說克隆後其物件的屬性值就是其最後一次修改。
如果想要實現深度克隆就可以將這個物件也實現介面Cloneable~~
程式碼:
先定義個類,沒有實現介面Cloneable
class Student {
public int id;
}
原型類中新增:
Student student ;
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
客戶端中新增
Student student = new Student();
student.id=1;
concretePrototype1.setStudent(student);
student.id=2;
concretePrototype2.setStudent(student);
student.id=3;
concretePrototype3.setStudent(student);
System.out.println("one:"+concretePrototype1.getNameString()+"studentid"+concretePrototype1.student.id);
System.out.println("two:"+concretePrototype2.getNameString()+"studentid"+concretePrototype2.student.id);
System.out.println("three:"+concretePrototype3.getNameString()+"studentid"+concretePrototype3.student.id);
最後輸出的都是id3
深度克隆:
讓其定義的類實現介面Cloneable,並實現clone方法
class Student implements Cloneable {
public int id;
Student student;
public Student clone(){
try {
student = (Student)super.clone();
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return student;
}
}
注意!!!!
要在原型類中給student類賦值的方法中呼叫clone即:
Student student ;
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = (Student)student.clone();
}
一定要,不這麼呼叫clone的話就等於還是淺度克隆。
傳入的student.clone方法返回一個物件。克隆他。
在客戶端中改變傳入的student。但是例項化的原型類是克隆的。原型類中的類物件也實現了介面Cloneable。所以也是深度克隆。恩,有點像遞迴的思想。
然後客戶端還是原來的樣子,但是輸出變了!
淺複製,被複制的物件的所有變數都含有與原來的物件相同的值,而所有的對其他物件的引用仍然指向原來的物件。
深複製把引用物件的變數指向複製的物件所引用的物件都複製一遍。
克隆還隱藏了物件建立的細節。 效能高
模板方法模式
模板方法模式就是把所有子類中不變的東西提取到父類中。減少程式碼的重複。
比如說試題。抄寫兩份給別人。
//所有試題類都有這些方法,所以提取出出來
class TestPaper{
public void TestQuestion1(){
System.out.println("1+1等於2");
}
public void TestQuestion2(){
System.out.println("2+1等於2");
}
public void TestQuestion3(){
System.out.println("2+2等於2");
}
}
class TestPaperA extends TestPaper{
public void TestQuestion1(){
super.TestQuestion1();
System.out.println("回答:"+"對");
}
public void TestQuestion2(){
super.TestQuestion2();
System.out.println("回答:"+"錯");
}
public void TestQuestion3(){
super.TestQuestion3();
System.out.println("回答:"+"對");
}
}
class TestPaperB extends TestPaper{
public void TestQuestion1(){
super.TestQuestion1();
System.out.println("回答:"+"對");
}
public void TestQuestion2(){
super.TestQuestion2();
System.out.println("回答:"+"對");
}
public void TestQuestion3(){
super.TestQuestion3();
System.out.println("回答:"+"對");
}
}
然後
public static void main(String[] args) {
TestPaperA A = new TestPaperA();
TestPaperB B = new TestPaperB();
A.TestQuestion1();
A.TestQuestion2();
A.TestQuestion3();
B.TestQuestion1();
B.TestQuestion2();
B.TestQuestion3();
}
}
這麼寫子類中很多方法都是重複的!。
將子類回答問題這個東西提取出來寫一個方法,讓方法返回這個答案。在問題方法中呼叫。那麼子類就不用寫super.問題方法了。只需要實現回答方法即可。
試題父類
class TestPaper{
public void TestQuestion1(){
System.out.println("1+1等於2"+"回答:"+Answer1());
}
public void TestQuestion2(){
System.out.println("2+1等於2"+"回答:"+Answer2());
}
public void TestQuestion3(){
System.out.println("2+2等於2"+"回答:"+Answer3());
}
public String Answer1(){
return null;
};
public String Answer2(){
return null;
};
public String Answer3(){
return null;
};
}
試題子類
class TestPaperA extends TestPaper{
public String Answer1(){
return "對";
};
public String Answer2(){
return "錯";
};
public String Answer3(){
return "對";
};
}
class TestPaperB extends TestPaper{
public String Answer1(){
return "對";
};
public String Answer2(){
return "對";
};
public String Answer3(){
return "對";
};
}
這麼寫程式碼很美。一定要在自己的程式碼中用到!