Youtube:

Enhanced .NET Unit Testing | David Gardiner

AutoFixture

https://github.com/AutoFixture/AutoFixture/

Approval Tests

Shouldly

dotMemory Unit

NBench

Sublime Shortcuts

super+l: select line (repeat select next lines)
super+d: select word (repeat select others occurrences in context for multiple editing)
ctrl+shift+m: select content into brackets.
super+shift+enter: insert line before.
super+enter: inter line after.
ctrl+shift+k: delete line.
super+k-k: delete from cursor to end of line.

{ "keys": ["ctrl+alt+s"], "command": "reveal_in_side_bar" },
{
"hot_exit": false,
"remember_open_files": false
}

It’s usually just easier to skip the mouse altogether—or it would be if Sublime didn’t mess up multiselect when word wrapping. Here’s the official documentation on using the keyboard and mouse for multiple selection. Since it’s a bit spread out, I’ll summarize it:

Where shortcuts are different in Sublime Text 3, I’ve made a note. For v3, I always test using the latest dev build; if you’re using the beta build, your experience may be different.

If you lose your selection when switching tabs or windows (particularly on Linux), try using Ctrl + U to restore it.

Mouse

Windows/Linux

Building blocks:


  • Positive/negative:


    • Add to selection: Ctrl

    • Subtract from selection: Alt In early builds of v3, this didn’t work for linear selection.


  • Selection type:


    • Linear selection: Left Click

    • Block selection: Middle Click or Shift + Right Click On Linux, middle click pastes instead by default.


Combine as you see fit. For example:


  • Add to selection: Ctrl + Left Click (and optionally drag)

  • Subtract from selection: Alt + Left Click This didn’t work in early builds of v3.

  • Add block selection: Ctrl + Shift + Right Click (and drag)

  • Subtract block selection: Alt + Shift + Right Click (and drag)

Mac OS X

Building blocks:


  • Positive/negative:


    • Add to selection:

    • Subtract from selection: ⇧⌘ (only works with block selection in v3; presumably bug)


  • Selection type:


    • Linear selection: Left Click

    • Block selection: Middle Click or + Left Click


Combine as you see fit. For example:


  • Add to selection: + Left Click (and optionally drag)

  • Subtract from selection: ⇧⌘ + Left Click (and drag—this combination doesn’t work in Sublime Text 3, but supposedly it works in 2)

  • Add block selection: ⌥⌘ + Left Click (and drag)

  • Subtract block selection: ⌥⇧⌘ + Left Click (and drag)

Keyboard

Windows


  • Return to single selection mode: Esc

  • Extend selection upward/downward at all carets: Ctrl + Alt + Up/Down

  • Extend selection leftward/rightward at all carets: Shift + Left/Right

  • Move all carets up/down/left/right, and clear selection: Up/Down/Left/Right

  • Undo the last selection motion: Ctrl + U

  • Add next occurrence of selected text to selection: Ctrl + D

  • Add all occurrences of the selected text to the selection: Alt + F3

  • Rotate between occurrences of selected text (single selection): Ctrl + F3 (reverse: Ctrl + Shift + F3)

  • Turn a single linear selection into a block selection, with a caret at the end of the selected text in each line: Ctrl + Shift + L

Linux


  • Return to single selection mode: Esc

  • Extend selection upward/downward at all carets: Alt + Up/Down Note that you may be able to hold Ctrl as well to get the same shortcuts as Windows, but Linux tends to use Ctrl + Alt combinations for global shortcuts.

  • Extend selection leftward/rightward at all carets: Shift + Left/Right

  • Move all carets up/down/left/right, and clear selection: Up/Down/Left/Right

  • Undo the last selection motion: Ctrl + U

  • Add next occurrence of selected text to selection: Ctrl + D

  • Add all occurrences of the selected text to the selection: Alt + F3

  • Rotate between occurrences of selected text (single selection): Ctrl + F3 (reverse: Ctrl + Shift + F3)

  • Turn a single linear selection into a block selection, with a caret at the end of the selected text in each line: Ctrl + Shift + L

Mac OS X


  • Return to single selection mode: (that’s the Mac symbol for Escape)

  • Extend selection upward/downward at all carets: ⌃⇧⇡, ⌃⇧⇣ (See note)

  • Extend selection leftward/rightward at all carets: ⇧⇠/⇧⇢

  • Move all carets up/down/left/right and clear selection: , , ,

  • Undo the last selection motion: ⌘U

  • Add next occurrence of selected text to selection: ⌘D

  • Add all occurrences of the selected text to the selection: ⌃⌘G

  • Rotate between occurrences of selected text (single selection): ⌥⌘G (reverse: ⌥⇧⌘G)

  • Turn a single linear selection into a block selection, with a caret at the end of the selected text in each line: ⇧⌘L

Notes for Mac users

On Yosemite and El Capitan, ⌃⇧⇡ and ⌃⇧⇣ are system keyboard shortcuts by default. If you want them to work in Sublime Text, you will need to change them:


  1. Open System Preferences.

  2. Select the Shortcuts tab.

  3. Select Mission Control in the left listbox.

  4. Change the keyboard shortcuts for Mission Control and Application windows (or disable them). I use ⌃⌥⇡ and ⌃⌥⇣. They defaults are ⌃⇡ and ⌃⇣; adding to those shortcuts triggers the same actions, but slows the animations.

In case you’re not familiar with Mac’s keyboard symbols:


  • is the escape key

  • is the control key

  • is the option/alt key

  • is the shift key

  • is the command key

  • et al are the arrow keys, as depicted

*Convert selection to lowercase (or uppercase) in Sublime Text?

Windows/Linux

Keypress Command
Ctrl + K, Ctrl + U Transform to Uppercase
Ctrl + K, Ctrl + L Transform to Lowercase

and for Mac:

Keypress Command
cmd + KU Transform to Uppercase
cmd + KL Transform to Lowercase

Also note that Ctrl + Shift + p in Windows (⌘ + Shift + p in a Mac) brings up the Command Palette where you can search for these and other commands.

* Typescript plugin Shortcuts

Feature Shortcut
Rename ^T ^M
Find references ^T ^R
Next reference ^T ^N
Prev reference ^T ^P
Format document ^T ^F
Format selection ^T ^F
Format line ^;
Format braces ^ Shift ]
Navigate to symbol ^ Alt R
Go to definition ^T^D or F12
Trigger completion ^Space
Trigger signature help Alt+,
See previous signature in the tooltip Alt + up
See next signature in the tooltip Alt + down
Paste and format ^V or ⌘V
Quick info ^T ^Q
Build (Win)^B or F7, (OSX) ⌘B or F7
Error list (via Command Palette)

EDMX (Entity Data Model XML) is an XML file which contains all the mapping details of how your objects map with SQL tables.

The EDMX file is further divided into three sections: CSDL, SSDL, and MSL.

  • SSDL (Storage Schema Definition Language) defines the mapping with your RDBMS data structure.

  • MSL (Mapping Schema Language) connects the CSDL and SSDL.

  • CSDL (Conceptual Schema definition language) is the conceptual abstraction which is exposed to the application.

What is the importance of T4 in Entity Framework?
T4 files are the heart of EF code generation. The T4 code templates read the EDMX XML file and generate C# behind code. This C# behind code is nothing but your entity and context classes.

How can we read records using Entity Framework classes?
In order to browse through records you can create the object of the context class and inside the context class you will get the records.

For instance, in the below code snippet we are looping through a customer object collection. This customer collection is the output given by the context class CustomermytextEntities.

CustomermytestEntities obj = new CustomermytestEntities();
foreach (Customer objCust in obj.Customers)
{}

How can we add, update, and delete using EF?
Create the object of your entity class, add it to the data context using AddObject method, and then call the SaveChanges method.

CustomermytestEntities obj = new CustomermytestEntities();
Customer objCust = new Customer();
objCust.CustomerCode = "1001";
obj.Customers.AddObject(objCust);
obj.SaveChanges();

If you want to update, select the object, make changes to the object, and call AcceptAllChanges.

CustomermytestEntities objContext = new CustomermytestEntities();
Customer objCustomer = (Customer)objContext.Customers.FirstOrDefault();
objCustomer.CountryCode = "NEP";
objContext.AcceptAllChanges();

If you want to delete, call the DeleteObject method as shown in the below code snippet:

CustomermytestEntities objContext = new CustomermytestEntities();
Customer objCustomer = (Customer)objContext.Customers.FirstOrDefault();
objContext.DeleteObject(objCustomer);

Models—the M in MVC—contain the data that users work with.
There are two broad types of model: view models, which represent just data passed from the controller to the view, and domain models, which contain the data in a business domain, along with the operations, transformations, and rules for creating, storing, and manipulating that data, collectively referred to as the model logic.

For each component in the MVC pattern, I’ll describe what should and should not be included. The model in an
application built using the MVC pattern should
Contain the domain data
Contain the logic for creating, managing, and modifying the domain data (even if that means executing remote logic via web services)
Provide a clean API that exposes the model data and operations on it The model should not
Expose details of how the model data is obtained or managed (in other words, details of the data storage mechanism or the remote web service should not be exposed to controllers and views)
Contain logic that transforms the model based on user interaction (because this is the controller’s job)
Contain logic for displaying data to the user (this is the view’s job)

Controllers are the connective tissue in an AngularJS web app, acting as conduits between the data model and views.
Controllers add business domain logic (known as behaviors) to scopes, which are subsets of the model.

A controller built using the MVC should
Contain the logic required to initialize the scope
Contain the logic/behaviors required by the view to present data from the scope
Contain the logic/behaviors required to update the scope based on user interaction
The controller should not
Contain logic that manipulates the DOM (that is the job of the view)
Contain logic that manages the persistence of data (that is the job of the model)
Manipulate data outside of the scope

The domain model isn’t the only data in an AngularJS application.

Controllers can create view data (also known as view model data or view models) to simplify the definition of views.

View data is not persistent and is created either by synthesizing some aspect of the domain model data or in response to user interaction.

Views should
Contain the logic and markup required to present data to the user Views should not
Contain complex logic (this is better placed in a controller)
Contain logic that creates, stores, or manipulates the domain model
Views can contain logic, but it should be simple and used sparingly. Putting anything but the simplest method
calls or expressions in a view makes the overall application harder to test and maintain.

Filter - Chapter 14

ng-class - Chapter 11

AngularJS tries to prevent tightly coupled components - Chapter 3.

$filter - Chapter 14

Services - Chapter 3

$http - Chapter 23

jQuery - Chapter 5, Chapter 20

JSON - Chapter 5

built-in directives - Chapter 9-12

Directives use jaLite - Chapter 15

Directives - Chapter 16

When AngularJS encounterrs the ng-include directive,

it makes an Ajax request, loads the file specified by the src attribute,

and inserts the contents in place of the element.

Services - Chapter 18

Directives are created by calling the directive method on an AngularJS module and passing in the name of the directive (cartSumary in this case)

angular.module("cart", [])
.directive("cartSummary", function (cart) { ... }

and a factory function that returns a directive definition object.

return {
restrict: "E",
templateUrl: "components/cart/cartSummary.html",
controller: function ($scope) {
var cartData = cart.getProducts();
$scope.total = function () {
var total = 0;
for (var i = 0; i < cartData.length; i++) {
total += (cartData[i].price * cartData[i].count);
}
return total;
}
$scope.itemCount = function () {
var total = 0;
for (var i = 0; i < cartData.length; i++) {
total += cartData[i].count;
}
return total;
}
}
};

Complete set of Directive properties in Chapters 16 and 17.

Name Description
restrict Sepcifies how the directive can be applied. I have used a value of E, which means that this directive can be applied only as an element. The most common value is EA, which means that the directive can be applied as an element or as an attribute.
templateUrl Specifies the URL of a partial view whose contents will be inserted in to the directive’s element.
controller Specifies a controller that will provide data and behaviors to the partial view.

AngularJS normalizes component names - Chapter 15.

URL routing - Chapter 22.

URl routing - it allows for different partial views to be displayed automatically based on the current URL.

ngRoute - angularjs-route.js

Call config method on the module object.

The config method takes a function as its argument, which is executed when the module is loaded but before the application is executed, providing an opportunity for any one-off configuration tasks.

angular.module("sportsStore", ["customFilters", "cart", "ngRoute"]) 
.config(function ($routeProvider) {} )

The function that I passed to the config method declares a dependency on a provider.

One of creating a service is that can be configured through a provider object, whose name is the concatenation of the service name and Provider.One

The $routeProvider that I have declared a dependency on is the provider for the $route service and is used to set up the URL routing in an application.

Create services with providers — Chapter 18

$route and $routeProvider — Chapter 22

*when

$routeProvider.when("/checkout", { ... });

*otherwise

$routeProvider.otherwise({ ... });

novalidate

disable any validation that the browser might try to perform.

URL routing feature to prevent AngularJS from displaying the view until the Ajax request has been completed. - Chapter 22

Use promises to build chains of behavior - Chapter 20

$animate - Chapter 23

complete set of configuration options use URL routes - Chapter 22

$http.post - Chapter 20

*$location - Chapter 11

$http - Chapter 20

how services work - Chapter 18

Scopes - Chapter 13

Understanding Dependency Injection

Using the Form Directive Attributes

Input

** Only works when the input element does not have a type attribute or when the type attribute is
text, url, email, or number.

name Description
ng-model Specifies a two-model binding, as descibed earlier in this chapter
ng-change Specifies an expression that is evaluated when the contents of the element are changed
ng-minlength Sets a minimum number of characters required for the element to be valid
ng-maxlength Sets a maximum number of characters required for the element to be valid
ng-pattern Sets a regular expression. The contents of the element must match this pattern in order to be valid
ng-required Sets the value of the required attribute with a data binding

Checkbox

The Attributes That Can Be Used for an input Element Whose type Attribute Is checkbox

Name Description
ng-model Specifies a two-model binding, as described earlier in this chapter
ng-change Specifies an expression that is evaluated when the contents of the element are changed
ng-true-value Specifies the value that the model binding expression will be set to when the element is checked
ng-false-value Specifies the value

Text Areas

name Description
ng-model Specifies a two-model binding, as descibed earlier in this chapter
ng-change Specifies an expression that is evaluated when the contents of the element are changed
ng-minlength Sets a minimum number of characters required for the element to be valid
ng-maxlength Sets a maximum number of characters required for the element to be valid
ng-pattern Sets a regular expression. The contents of the element must match this pattern in order to be valid
ng-required Sets the value of the required attribute with a data binding

Select

name Description
ng-options
ng-required

ng-options="item.action for item in todos"

<select ng-model="selectValue" ng-options="item.action for item in todos">
<option value="">(Pick One)</option>
</select>
<select ng-model="selectValue" ng-options="item.id as item.action for item in todos">
<option value="">(Pick One)</option>
</select>
ng-options="item.action group by item.place for item in todos">
ng-options="item.id as item.action group by item.place for item in todos">

Using the Services Method

var baseLogger = function () {

this.messageCount = 0;

this.log = function (msg) {
console.log(this.msgType + ": " + (this.messageCount++) + " " + msg);
}
};

var debugLogger = function () { };

debugLogger.prototype = new baseLogger();

debugLogger.prototype.msgType = "Debug";

var errorLogger = function () { };

errorLogger.prototype = new baseLogger();

errorLogger.prototype.msgType = "Error";

angular.module("customServices", [])
.service("logService", debugLogger)
.service("errorService", errorLogger);

Using Factory Method

angular.module("customServices", [])
.factory("logService", function () {
var messageCount = 0;
return {
log: function (msg) {
console.log("(LOG + " + messageCount++ + ") " + msg);
}
};
});
angular.module("customServices", [])
.provider("logService", function(){
return {
$get: function() {
return {
messageCount: 0,
log: function(msg) {
console.log("(LOG + " + this.messageCount++ + ") " + msg);
}
};
}
};
});

Table 9-3. The Members of the Module Object

Name Description
animation(name, factory) Supports the animation feature, which I describe in Chapter 23.
config(callback) Registers a function that can be used to configure a module when it is loaded. See the “Working with the Module Life Cycle” section for details.
constant(key, value) Defines a service that returns a constant value. See the “Working with the Module Life Cycle” section later in this chapter.
controller(name, constructor) Creates a controller. See Chapter 13 for details.
directive(name, factory) Creates a directive, which extends the standard HTML vocabulary. See Chapters 15–17.
factory(name, provider) Creates a service. See Chapter 18 for details and an explanation of how this method differs from the provider and service methods.
filter(name, factory) Creates a filter that formats data for display to the user. See Chapter 14 for details.
provider(name, type) Creates a service. See Chapter 18 for details and an explaination of how this method differs from the service and factory methods.
name Returns the name of the module.
run(callback) Registers a function that is invoked after AngularJS has loaded and configured all of the modules. See the “Working with the Module Life Cycle” section for details.
service(name, constructor) Creates a service. See Chapter 18 for details and an explanation of how this method differs from the provider and factory methods.
value(name, value) Defines a service that returns a constant value; see the “Defining Values” section later in this chapter.

List:

Problem Solution Listing
Define a service. Use the Module.service, Module.factory, or Module.provider method. 12
Define a service from an existing object or value. Use the Module.value method. 13
Add structure to the code in an application. Create multiple modules and declare dependencies from the module referenced by the ng-app attribute. 14–16
Register functions that are called when modules are loaded. Use the Module.config and Module.run methods. 17
angular.module("customServices", [])
.provider("logService", function(){
return {
$get: function() {
return {
messageCount: 0,
log: function(msg) {
console.log("(LOG + " + this.messageCount++ + ") " + msg);
}
};
}
};
});

Simple Sample.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GossipDesignPattern.SimpleFactory
{
class Program
{
static void Main(string[] args)
{

Console.Write("input first number:");
string A = Console.ReadLine();

Console.Write("(+,-,*,/): ");
string B = Console.ReadLine();

Console.WriteLine("input second number:");

string C = Console.ReadLine();

string D = "";

if (B == "+")
D = Convert.ToString(Convert.ToDouble(A) + Convert.ToDouble(C));
if (B == "-")
D = Convert.ToString(Convert.ToDouble(A) - Convert.ToDouble(C));
if (B == "*")
D = Convert.ToString(Convert.ToDouble(A) * Convert.ToDouble(C));
if (B == "/")
D = Convert.ToString(Convert.ToDouble(A) / Convert.ToDouble(C));

Console.WriteLine("result: " + D);
}
}

class ProgramV2
{
static void Main(string[] args)
{

try
{
Console.Write("input first number:");
string strNumberA = Console.ReadLine();

Console.Write("(+,-,*,/): ");
string strOperate = Console.ReadLine();

Console.WriteLine("input second number:");
string strNumberB = Console.ReadLine();

string strResult = "";

switch (strOperate)
{
case "+":
strResult = Convert.ToString(Convert.ToDouble(strNumberA) + Convert.ToDouble(strNumberB));
break;
case "-":
strResult = Convert.ToString(Convert.ToDouble(strNumberA) - Convert.ToDouble(strNumberB));
break;
case "*":
strResult = Convert.ToString(Convert.ToDouble(strNumberA) * Convert.ToDouble(strNumberB));
break;
case "/":
if (strNumberB != "0")
strResult = Convert.ToString(Convert.ToDouble(strNumberA) / Convert.ToDouble(strNumberB));
else
strResult = "Divisor can't be 0";
break;
}
Console.WriteLine("result: " + strResult);

Console.ReadLine();
}
catch (Exception ex)
{
Console.WriteLine("Error input:" + ex.ToString());
}
}
}

public class Operation
{
public static double GetResult(double numberA, double numberB, string operate)
{

double result = 0d;
switch (operate)
{
case "+":
result = numberA + numberB;
break;
case "-":
result = numberA - numberB;
break;
case "*":
result = numberA * numberB;
break;
case "/":
result = numberA / numberB;
break;
}

return result;
}

static void Main(string[] args)
{

try
{
Console.Write("input first number:");
string strNumberA = Console.ReadLine();

Console.Write("(+,-,*,/): ");
string strOperate = Console.ReadLine();

Console.WriteLine("input second number:");
string strNumberB = Console.ReadLine();

string strResult = "";

strResult = Convert.ToString(Operation.GetResult(Convert.ToDouble(strNumberA), Convert.ToDouble(strNumberB), strOperate));

Console.WriteLine("result: " + strResult);

Console.ReadLine();
}
catch (Exception ex)
{
Console.WriteLine("Error input:" + ex.ToString());
}
}
}

public class OperationBase
{
private double _numberA = 0;
private double _numberB = 0;

public double NumberA {
get { return _numberA; }
set { _numberA = value; }
}

public double NumberB
{
get { return _numberB; }
set { _numberB = value; }
}

public virtual double GetResult()
{

double result = 0;
return result;
}
}

class OperationAdd : OperationBase
{
public override double GetResult()
{

double result = 0;
result = NumberA + NumberB;
return result;
}
}

class OperationSub : OperationBase
{
public override double GetResult()
{

double result = 0;
result = NumberA - NumberB;
return result;
}
}

class OperationMul : OperationBase
{
public override double GetResult()
{

double result = 0;
result = NumberA * NumberB;
return result;
}
}

class OperationDiv : OperationBase
{
public override double GetResult()
{

double result = 0;
if (NumberB == 0)
throw new Exception("Divisor can't be 0");

result = NumberA / NumberB;

return result;
}
}

public class OperationFactory
{
public static OperationBase CreateOperate(string operate)
{

OperationBase oper = null;
switch (operate)
{
case "+":
oper = new OperationAdd();
break;
case "-":
oper = new OperationSub();
break;
case "*":
oper = new OperationMul();
break;
case "/":
oper = new OperationDiv();
break;
}

return oper;
}

static void main(string[] args)
{

OperationBase oper;
oper = OperationFactory.CreateOperate("+");
oper.NumberA = 1;
oper.NumberB = 2;
double result = oper.GetResult();
}
}

public class FactoryMethod
{

interface IFactory
{
OperationBase CreateOperation();
}

class AddFactory : IFactory
{
public OperationBase CreateOperation()
{

return new OperationAdd();
}
}

class SubFactory : IFactory
{
public OperationBase CreateOperation()
{

return new OperationSub();
}
}

class MulFactory : IFactory
{
public OperationBase CreateOperation()
{

return new OperationMul();
}
}

class DivFactory : IFactory
{
public OperationBase CreateOperation()
{

return new OperationDiv();
}
}

static void main(string[] args)
{

IFactory operFactory = new AddFactory();
OperationBase oper = operFactory.CreateOperation();
oper.NumberA = 1;
oper.NumberB = 2;
double result = oper.GetResult();
}
}
}

LeiFeng.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GossipDesignPattern.SimpleFactory
{
// 简单工厂模式的最大优点在于工厂类中包含了必要的逻辑判断, 根据客户端的选择条件动态实例化相关的类,对于客户端来说,去除了与具体产品的依赖。
class LeiFeng
{
public void Sweep()
{

Console.WriteLine("Sweep!");
}

public void Wash()
{

Console.WriteLine("Wash!");
}

public void BuyRice()
{

Console.WriteLine("Buy Rice!");
}
}

class Undergraduate: LeiFeng
{
public void IamUndergraduate()
{

Console.WriteLine("I am undergraduate!");
}
}

class ProgramV3
{
static void main(string [] args)
{

LeiFeng xueleifeng = new Undergraduate();

xueleifeng.BuyRice();
xueleifeng.Sweep();
xueleifeng.Wash();

LeiFeng student1 = new Undergraduate();
student1.BuyRice();

LeiFeng student2 = new Undergraduate();
student1.Sweep();

LeiFeng student3 = new Undergraduate();
student1.Wash();
}
}

class Volunteer : LeiFeng
{
}

class SimpleFactory
{
public static LeiFeng CreateLeiFeng(string type)
{

LeiFeng result = null;
switch (type)
{
case "Undergraduate":
result = new Undergraduate();
break;
case "Volunteer":
result = new Volunteer();
break;
}

return result;
}

static void main(string[] args)
{

LeiFeng studentA = SimpleFactory.CreateLeiFeng("Undergraduate");

studentA.BuyRice();

LeiFeng studentB = SimpleFactory.CreateLeiFeng("Undergraduate");

studentB.Sweep();

LeiFeng studentC = SimpleFactory.CreateLeiFeng("Undergraduate");

studentC.Wash();
}
}

//工厂方法克服了简单工厂违背开放-封闭原则的缺点,又保持了封装对象创建过程的优点
class FactoryMethodForLeiFeng
{
interface ILeiFengFactory
{
LeiFeng CreateLeiFeng();
}

class UndergraduateFactory : ILeiFengFactory
{
public LeiFeng CreateLeiFeng()
{

return new Undergraduate();
}
}

class VolunteerFactory : ILeiFengFactory
{
public LeiFeng CreateLeiFeng()
{

return new Volunteer();
}
}

static void main(string[] args)
{

ILeiFengFactory factory = new UndergraduateFactory();

LeiFeng student = factory.CreateLeiFeng();

student.BuyRice();
student.Sweep();
student.Wash();
}
}
}