1. 程式人生 > >如何需要一套試題——原型模式、模板模式

如何需要一套試題——原型模式、模板模式

原型模式、模板模式

如果需要影印一套試卷,分發給沒一個學生做,那麼,我們應該需要哪一個模式?

很明顯,首先我們需要不斷的去複製試卷,為試卷類建立例項,但是,我們知道,一套試卷的建立過程是比較複雜的,因為他包含選擇、填空、問答等題型,在執行這個建構函式會消耗較長的時間,同時,試卷建構函式的資訊由沒有什麼變化,那麼,用new來建立是不是太昂貴了?

那麼,最好的解決方法,就是用克隆,通過複製現在已經有了的例項來建立新的例項。

一般在初始化的資訊不發生變化的情況下,克隆是最好的辦法。這既隱藏了物件建立的細節,有對效能呢大大的提高。

其實上面所提到的就是下--原型模式(Prototype),

原型模式程式碼:

//原型類
abstract class Prototype
{
 private string id;
 public Prototype(string id)
 {
  this.id = id;
 }

 public string Id
 {
  get { return id; }
 }

 public abstract Prototype Clone();
}
//具體原型類
class ConcretePrototype1 : Prototype
{
 public ConcretePrototype1(string id) :base(id)
 {
 }

 public override Prototype Clone()
 {
  return (Prototype)this.MemberwiseClone();
 }
}

客戶端程式碼:
//測試程式碼
static void Main(string[] args)
{
 ConcretePrototype1 p1 = new ConcretePrototype1("I");
 ConcretePrototype1 c1 = (ConcretePrototype1)p1.Clone();
 Console.WriteLine("Cloned:{0}", c1.Id);
 Console.ReadLine();
}

MemberwiseClone()這裡對於複製由個問題:MemberwiseClone 方法建立一個淺表副本,方法是建立一個新物件,然後將當前物件的非靜態欄位複製到該新物件。
 如果欄位是值型別的,則對該欄位執行逐位複製。 如果欄位是引用型別,則複製引用但不復制引用的物件;因此,原始物件及其複本引用同一物件。(參見MSDN)

所以,如果您用MemberwiseClone方法複製,但是不符合您的結果,試試下面的方法

  • 呼叫要複製的物件的類建構函式以建立含有從第一個物件中提出的屬性值的第二個物件。 這假定物件的值完全由類建構函式定義。

  • 呼叫 MemberwiseClone 方法建立的物件的淺表副本,然後將指定新的物件,其值均相同,原始物件的任何屬性或欄位的值是引用型別。 該示例中的DeepCopy 方法闡釋了這種方法。

  • 序列化要深層複製的物件,然後將序列化的資料還原到另一個物件變數。

  • 使用帶遞迴的反射執行的深層複製操作。

試卷影印用原型方法比較適合,可以,如何實現學生答卷的方法呢?

首先,我們先來看看學生答卷的特點:學生答題必須每一題都是不同的答案,不同的學生必須有不同的答案。

其次,我們看看原型方法的特點:原型方法是把A複製給B,B複製給C,如果B與A有一點不同可以單獨設定。

最後分析:如果我們設定一份樣卷,每一個題有自己的答案,或者把答案設定為空,然後,由A、B、C三個同學複製此樣卷,然後把答案部分修改,這樣,就可以實現每個學生答題的問題。

可是,這裡有個問題,我們雖然可以修改原型模式的一些地方,但是,如果對於答案這種大規模修改的問題,顯然就違背了原型模式中的不需要知道任何建立細節,只需複製就可以的設計原則,而此時在使用原型模式就顯得畫蛇添足了,而且原型模式屬於建立型模式,對於答題對物件修改的問題,顯得有些力不從心。

那麼,由此可見,對於答卷的問題,我們需要的是像原型模式一樣,把問題可以放在一個地方,提供一個問題程式碼複用的平臺,而把答案這些時刻變化的東西和問題分開,來實現答題需求。也就是定義一個操作中的演算法的骨架,而將一些步驟延遲到子類中,這也就是我們所說的模板方法模式。

模板方法模式使得子類可以不改變一個演算法的結構即可重定義該演算法的某些特定步驟


程式碼實現:

//AbstractClass是抽象類,其實也就是一抽象模板,定義並實現了一個模板方法。這個模板方法一般是一個具體方法,它給出了一個頂級邏輯骨架,而邏輯的組成步驟在相應的抽象操作中,推遲到子類實現。頂級邏輯也有可能呼叫一些具體方法。
public abstract class AbstractClass
{
	public abstract void primitiveOperation1();

	public abstract void primitiveOperation2();

	public void templateMethod()
	{
		primitiveOperation1();
		primitiveOperation2();
	}
}
//ConcreteClass,實現父灰所定義的一個或多個抽象方法。每一個AbstractClass都可以有任意多個ConcreteClass與之相對應,而每一個ConcreteClass都可以給出這些抽象方法(也就是頂級邏輯的組成步驟)的不同,從而使得頂級邏輯的實現各不相同。
public class ConcreteClassA extends AbstractClass
{
	@Override
	public void primitiveOperation1()
	{
		System.out.println("具體類A方法1實現");
	}

	@Override
	public void primitiveOperation2()
	{
		System.out.println("具體類A方法2實現");
	}
}
public class ConcreteClassB extends AbstractClass
{
	@Override
	public void primitiveOperation1()
	{
		System.out.println("具體類B方法1實現");
	}

	@Override
	public void primitiveOperation2()
	{
		System.out.println("具體類B方法2實現");
	}
}
//客戶端程式碼
public class Main
{
	public static void main(String[] args)
	{
		AbstractClass c;

		c = new ConcreteClassA();
		c.templateMethod();

		c = new ConcreteClassB();
		c.templateMethod();
	}
}


答題程式碼:

//試題父類
public class TestPaper
{
	public void testQuestion1()
	{
		System.out.println("楊過得到,後來給了郭靖,練成倚天劍、屠龍刀的玄鐵可能是[] "
				+ "a.球磨鑄鐵 b.馬口鐵 c.高速合金鑰 d.碳素纖維");

		System.out.println("答案:" + answer1());
	}

	public void testQuestion2()
	{
		System.out.println("楊過、程英、陸無雙剷除了情花.造成[] " + "a.使這種植物不再害人 b.使一種珍稀物種滅絕 "
				+ "c.破壞了那個生物圈的生態平衡 d.造成該地區沙漠化");

		System.out.println("答案:" + answer2());
	}

	public void testQuestion3()
	{
		System.out.println("藍鳳凰致使華山師徒、桃谷六仙嘔吐不止,如果你是大夫,會給他們開什麼藥[] "
				+ "a.阿司匹林 b.牛黃解毒片 c.氟呱酸 d.讓他們喝大量的生牛奶 e.以上全不對");

		System.out.println("答案:" + answer3());
	}

	protected String answer1()
	{
		return "";
	}

	protected String answer2()
	{
		return "";
	}

	protected String answer3()
	{
		return "";
	}
}
//學生甲抄試卷類
public class TestPaperA extends TestPaper
{
	protected String answer1()
	{
		return "b";
	}

	protected String answer2()
	{
		return "c";
	}

	protected String answer3()
	{
		return "a";
	}
}
//學生乙抄試卷類
public class TestPaperB extends TestPaper
{
	protected String answer1()
	{
		return "c";
	}

	protected String answer2()
	{
		return "a";
	}

	protected String answer3()
	{
		return "a";
	}
}
//客戶端程式碼
public class Main
{
	public static void main(String[] args)
	{
		System.out.println("學生甲抄的試卷:");
		TestPaper studentA = new TestPaperA();
		studentA.testQuestion1();
		studentA.testQuestion2();
		studentA.testQuestion3();

		System.out.println("學生乙抄的試卷:");
		TestPaper studentB = new TestPaperB();
		studentB.testQuestion1();
		studentB.testQuestion2();
		studentB.testQuestion3();
	}
}


這裡直接借用大話設計模式我程式碼。

我沒可以看出,模板方法模式和原型模式雖然都實現我們現實中“影印”的功能,但是,

模板方法的優點:
1.封裝不變部分,擴充套件可變部分。
把認為是不變部分的演算法封轉到父類實現中,而可變部分的則可以通過繼承來繼續擴充套件。
2.提取公共部分程式碼,便於維護。
3.行為由父類控制,子類來實現。

所以,原型模式在影印時意在“拷貝”,主要是減輕new帶來的壓力,而修改只是一小部分,而模板方法模式是在封裝不變,擴充套件可變,這裡可變式必要的一部分,所以,影印也有影印的不同。

所以,剛開始學設計模式的時候感覺很多模式很亂,總是感覺這麼多設計模式都差不多,不知道到底該在什麼時候用,我想,對比,知其本質,也許這樣對比存在很大的問題,但是給一個故事作為背景,對於應用不也是一個不錯的辦法嗎?


相關推薦

如何需要試題——原型模式模板模式

原型模式、模板模式 如果需要影印一套試卷,分發給沒一個學生做,那麼,我們應該需要哪一個模式? 很明顯,首先我們需要不斷的去複製試卷,為試卷類建立例項,但是,我們知道,一套試卷的建立過程是比較複雜的,因為他包含選擇、填空、問答等題型,在執行這個建構函式會消耗較長的時間,同

裝飾模式原型模式模板模式享元模式

相似點 這幾個從名字上都看出有複用的意思, 裝飾模式:通過對A裝飾獲得B,B擁有A的功能; 原型模型:通過clone A獲得B,B也有A的功能; 模板模式:B通過繼承A,B擁有A的功能; 享元模式:其實享元模式不應該和其他三個在一起比較,因為其他三個傾向於複用,而享元傾向於

spring原始碼分析---策略模式原型模式模板模式

策略模式 —–> 用於回撥處理 import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; p

大話設計模式-----(三)工廠方法模式原型模式模板方法模式

工廠方法模式 簡單工廠模式是恩,按那個計算器來寫的話,就是把運算子都具有的特性抽象出來作為父類。然後想新增運算型別,只需要對應的增加繼承其運算子抽象類,然後新增自己的運算方法即可。但是要在工廠類中修改switch 增加判斷。 對應的工廠方法模式就是把工廠類這

設計模式C++實現(5)——原型模式模板方法模式

       軟體領域中的設計模式為開發人員提供了一種使用專家設計經驗的有效途徑。設計模式中運用了面向物件程式語言的重要特性:封裝、繼承、多型,真正領悟設計模式的精髓是可能一個漫長的過程,需要大量實踐經驗的積累。最近看設計模式的書,對於每個模式,用C++寫了個小例子,加深一

C++原型模式模板模式

hide 完成 return enc span person info 步驟 招聘 DP書上的定義為:用原型實例指定創建對象的種類,並且通過拷貝這些原型創建新的對象。其中有一個詞很重要,那就是拷貝。可以說,拷貝是原型模式的精髓所在。舉個現實中的例子來介紹原型模式。找工作

(*)(轉)要快速學習SSM框架,你需要學習曲線平滑的教程

lan 都是 spring 學習方式 能夠 分享圖片 個人能力 很多 data 作者:meepo鏈接:https://www.zhihu.com/question/57719761/answer/156952139來源:知乎著作權歸作者所有。商業轉載請聯系作者獲得授權,非商

JS面向對象基礎講解(工廠模式構造函數模式原型模式混合模式動態原型模式)

由於 不能識別 訪問 rip 思想 sta info hang eat 這篇文章主要介紹了面向對象JS基礎講解,工廠模式、構造函數模式、原型模式、混合模式、動態原型模式,需要的朋友可以參考下 什麽是面向對象?面向對象是一種思想!(廢話)。   面向對象可以把程序中的關

《設計模式》之一文帶你理解建造者模式模板方法介面卡模式外觀模式

我的github,到時上傳例子程式碼 https://github.com/tihomcode 《設計模式》之一文帶你理解單例、JDK動態代理、CGLIB動態代理、靜態代理 建造者模式 什麼是建造者模式 建造者模式:是將一個複雜的物件的構建與它的表示分離,使得

javaSE (三十八)設計模式 ( 單例設計模式(餓漢式/懶漢式)簡單工廠模式工廠模式介面卡模式模板方法設計模式

1、單例設計模式(餓漢式/懶漢式): 概念:保證類在記憶體中只有一個物件 思路: 私有構造方法,其他類不能再訪問該構造方法了 建立本類物件(就在本類裡建立),將物件的應用作為成員變數,並私有靜態化(在這裡又分為餓漢式和懶漢式,餓漢式直接引用連線物件,而懶漢式在第二步先建

js 繼承()之原型借用建構函式組合繼承

前言 … Just we 原型鏈 基本思想利用原型讓一個引用型別繼承另一個引用型別的屬性和方法 function Father() { this.last_name = '張' } Father.prototype.sayLast_Name = fu

《設計模式》之一文帶你理解策略模式原型模式(深淺拷貝)觀察者模式裝飾模式

原型模式 什麼是原型模式 原型模式是一個建立型的模式。原型二字表明瞭該模式應該有一個樣板例項,使用者從這個樣板物件中複製一個內部屬性一致的物件,這個過程也就是我們稱的“克隆”。被複制的例項就是我們所稱的“原型”,這個原型是可定製的。原型模式多用於建立複雜

JS面向物件基礎講解(工廠模式建構函式模式原型模式混合模式動態原型模式)

什麼是面向物件?面向物件是一種思想!(廢話)。   面向物件可以把程式中的關鍵模組都視為物件,而模組擁有屬性及方法。這樣我們如果把一些屬性及方法封裝起來,日後使用將非常方便,也可以避免繁瑣重複的工作。接下來將為大家講解在JS中面向物件的實現。    工廠模式   工廠模式是軟體工程領

設計模式模板模式

模板模式是執行的流程不能更改,但是流程中的某些細節是根據不同的場景而由使用者自定義實現細節。   例如JDBC的查詢步驟: 獲取連線 建立statement物件 設定引數 執行語句,並獲取結果集 解析結果集 關閉結果集 關閉statement 關閉連線 我

設計模式() 觀察者模式裝飾模式工廠模式

               ---------------------- ASP.Net+Android+IOS開發、.Net培訓、期待與您交流! ---------------------- 1.觀察者模式 觀察者模式:  定義了物件之間的一對多依賴,這樣一來,當一

2014騰訊校招筆試題分析----資料結構篇(試題引發的血案)

一 不定項選擇題(共25題,每題4分,共100分,少選、錯選、多選均不得分) 1 已知一棵二叉樹,如果先序遍歷的節點順序是:ADCEFGHB,中序遍歷是:CDFEGHAB,則後序遍歷結果為:(D) A.CFHGEBDA   B.CDFEGHBA   C.FGHCDEB

Effective Java學習筆記(靜態工廠方法JavaBeans模式builder模式

靜態工廠方法代替構造器 對於類而言,為了讓客戶端獲取它自身的一個例項,最常用的辦法是提供一個公有的構造器。還有一種方法:公有的靜態工廠方法。它只是一個返回類例項的靜態方法,如下程式碼所示: public class Gender { pri

設計模式模板方法模式策略模式命令設計模式

一、模板方法模式 模板方法模式需要開發抽象類和具體子類的設計師之間的協作。一個設計師負責給出一個演算法的輪廓和骨架,另一些設計師則負責給出這個演算法的各個邏輯步驟。代表這些具體邏輯步驟的方法稱做基本方法(primitive method);而將這些基本方法彙總起來的方法叫做

單例模式工廠模式抽象模式模板方法模式

一:單例模式 1.定義:單例模式確保某一個類智慧建立一個物件。 2.單例模式的實現主要是把構造器設定為private,外部通過Singleton.getInstance()來訪問。通用類圖: 3.單例模式實現的三種方式: (1)立即載入/餓漢模式,即在呼叫方法前,例項已經

JavaScript設計模式)單例模式組合模式和外觀模式

單例模式是指在您要確保始終只建立一個物件例項時使用的設計模式。 在面向物件的經典程式語言中,建立單例模式背後的概念多少有點讓人難以理解,因為其中包含一個同時具有靜態及非靜態屬性和方法的類。 但本文主要討論 JavaScript,因此,由於 JavaScript 是一種不包含真正類的動態語言,因此 Java