软件体系结构设计原则
一【实验目的】
- 理解面向对象设计原则的基本概念
- 掌握主要设计原则的概念、实现方法和实例
二【实验内容】
1.里氏替换原则
举一个符合里氏替换原则的例子,用代码实现
里氏替换原则:
• 子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法
• 子类中可以增加自己特有的方法
• 当子类的方法重载父类的方法时,方法的前置条件(即方法的输入参数)要比父类的方法更宽松
• 当子类的方法实现父类的方法时(重写/重载或实现抽象方法),方法的后置条件(即方法的的输出/返回值)要比父类的方法更严格或相等
代码实例:
using System;
namespace lishitihuan
{
class Program
{
static void Main(string[] args)
{
Animal animal1 = new Tiger(); //通过多态创建老虎对象
Animal animal2 = new Cat(); //通过多态创建猫对象
animal1.setRunSpeed(30);
animal2.setRunSpeed(20);
Console.WriteLine("如果奔跑300公里");
Console.WriteLine("那么老虎将奔跑" + animal1.getRunSpeed(300));
Console.WriteLine("那么猫将奔跑" + animal2.getRunSpeed(300));
}
}
class Animal
{
private double runSpeed;
private double flySpeed;
public void setRunSpeed(double speed)
{
this.runSpeed = speed;
}
public double getRunSpeed(double distance)
{
return distance / runSpeed;
}
}
class Tiger :Animal //定义老虎类,直接继承动物类的方法
{
}
class Cat : Animal //定义猫类,直接继承动物类的方法
{
}
}
2.依赖倒置原则
举一个符合依赖倒置原则 的例子,用代码实现
依赖倒置原则:
• 每个类尽量提供接口或抽象类,或者两者都具备。
• 变量的声明类型尽量是接口或者是抽象类。
• 任何类都不应该从具体类派生。
• 使用继承时尽量遵循里氏替换原则。
实例代码如下:
using System;
namespace yilaidaozhi
{
class Program
{
static void Main(string[] args)
{
Customer customer = new Customer(); //初始化顾客类
Console.WriteLine("顾客购买以下商品");
customer.shopping(new ZhangsanShop()); //顾客执行shopping方法,参数是对应的商店对象
customer.shopping(new LisiShop());
}
}
interface Shop
{
public String sell(); //定义接口Shop以及抽象方法
}
class ZhangsanShop :Shop{
public String sell()
{
return "张三商店销售的东西"; //实现接口以及抽象方法
}
}
class LisiShop : Shop
{
public String sell()
{
return "李四商店销售的东西"; //实现接口以及抽象方法
}
}
class Customer
{
public void shopping(Shop shop)
{
Console.WriteLine("顾客买到"+shop.sell()); //定义顾客类以及购买方法
}
}
}
3. 接口隔离原则
举一个符合接口隔离原则的例子,用代码实现
• 接口尽量小,但是要有限度。一个接口只服务于一个子模块或业务逻辑。
• 为依赖接口的类定制服务。只提供调用者需要的方法,屏蔽不需要的方法。
• 了解环境,拒绝盲从。每个项目或产品都有选定的环境因素,环境不同,接口拆分的标准就不同深入了解业务逻辑。
• 提高内聚,减少对外交互。使接口用最少的方法去完成最多的事情。
例子:宠物狗和鸽子都有着捕食(hunt)行为,但是又都有着各自的特有的方法,比如宠物狗有奔跑(run)和行走(walk)行为,而鸽子有滑翔(glide)和飞翔(fly)行为,如果将所有行为设置成一个接口,然后宠物狗和鸽子去继承这一个接口,那么势必会造成接口的代码冗余。
实例:
using System;
namespace ISP
{
/// <summary>
/// 接口隔离原则
/// </summary>
class Program
{
static void Main(string[] args)
{
Dog dog = new Dog();
PetDog petDog = new PetDog();
dog.hunt(petDog);
dog.run(petDog);
dog.walk(petDog);
Bird bird = new Bird();
Dove dove = new Dove();
bird.fly(dove);
bird.glide(dove);
bird.hunt(dove);
}
}
interface BehaviorOne
{
void hunt(); //捕食行为
}
interface BehaviorTwo
{
void walk(); //行走行为
void run(); //奔跑行为
}
interface BehaviorThree
{
void glide(); //滑翔行为
void fly(); //飞翔行为
}
class Dog
{
public void hunt(BehaviorOne one)
{
one.hunt();
}
public void walk(BehaviorTwo two)
{
two.walk();
}
public void run(BehaviorTwo two)
{
two.run();
}
}
class PetDog :BehaviorOne,BehaviorTwo
{
public void hunt()
{
Console.WriteLine("宠物狗:我喜欢吃狗粮");
}
public void walk()
{
Console.WriteLine("宠物狗:我喜欢行走");
}
public void run()
{
Console.WriteLine("宠物狗:我喜欢奔跑");
}
}
class Bird
{
public void hunt(BehaviorOne one)
{
one.hunt();
}public void fly(BehaviorThree three)
{
three.fly();
}public void glide(BehaviorThree three)
{
three.glide();
}
}
class Dove : BehaviorOne, BehaviorThree
{
public void fly()
{
Console.WriteLine("鸽子:我喜欢飞翔");
}
public void glide()
{
Console.WriteLine("鸽子:我喜欢滑翔");
}
void BehaviorOne.hunt()
{
Console.WriteLine("鸽子:我喜欢吃东西");
}
}
}
4.迪米特法则
举一个符合迪米特法则的例子,用代码实现
从依赖者的角度来说,只依赖应该依赖的对象。
从被依赖者的角度说,只暴露应该暴露的方法。
例子:明星由于全身心投入艺术,所以许多日常事务由经纪人负责处理,如与粉丝的见面会,与媒体公司的业务合作等。这里的经纪人是明星的朋友,而粉丝和媒体公司是陌生人,所以适合使用迪米特法则。
代码如下:
using System;
namespace LKP
{
/// <summary>
/// 迪米特法则(最少知道原则)
/// </summary>
class Program
{
static void Main(string[] args)
{
Agent agent = new Agent();
agent.setStar(new Star("渣渣林"));
agent.setFans(new Fans("渣渣粉"));
agent.setCompany(new Company("渣渣潮流股份有限公司"));
agent.meetFans();
agent.meetCompany();
}
}
class Star
{
private String name;
public Star(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
}
class Agent
{
private Star myStar;
private Company myCompany;
private Fans myFans;
public void setStar(Star myStar)
{
this.myStar = myStar;
}
public void setFans(Fans myFans)
{
this.myFans = myFans;
}
public void setCompany(Company myCompany)
{
this.myCompany = myCompany;
}
public void meetFans()
{
Console.WriteLine(myStar.getName() + "与" + myFans.getName() + "见面了");
}
public void meetCompany()
{
Console.WriteLine(myStar.getName() + "和" + myCompany.getName() + "见面了");
}
}
class Company
{
private String name;
public Company(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
}
class Fans
{
private String name;
public Fans(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
}
}
5. 开闭原则
举一个符合开闭原则的例子,用代码实现
例子:猫和狗都会叫,但是叫的方式不同,所以可以让他们同时继承一个Pet类,里面设一个抽象方法say(),继承之后实现抽象方法,就可以实现不修改源代码,只修改代码就能增加一个宠物了。
代码:
using System;
namespace OCP
{
class Program
{
static void Main(string[] args)
{
Pet dog = new Dog();
dog.say();
Pet cat = new Cat();
cat.say();
}
abstract class Pet
{
public abstract void say();
}
class Dog:Pet
{
public override void say()
{
Console.WriteLine("狗叫:汪汪汪");
}
}
class Cat : Pet
{
public override void say()
{
Console.WriteLine("猫叫:喵喵喵");
}
}
}
}
遇到的问题:在学习各种设计模式方法的时候,对它们里面的方法调用以及该传什么参数等等还不是很熟悉,在开闭原则的使用的时候用到了多态,还有所有原则都用到了继承和实现接口,C#语言的这些语法忘了很多。
解决方法:在学习这些原则的同时对C#编程的继承和接口以及多态的这一部分又重新复习了一下,基本掌握了这些之后学这些原则就不是那么吃力了。
感想:代码以及各种原则如果想要彻底熟悉必须要多见见例子,多敲敲代码,不能仅仅是看,那样只会使纸上谈兵。对于软件设计模式,虽然现在一些小体量的程序用不到,但是以后软件体量大了,这些方法一定会着手使用。所以自己必须要熟练掌握。