简化的装饰图案。这是正确的吗?

时间:2017-10-22 21:28:07

标签: c# .net design-patterns decorator

所以我创造了这样的东西:

interface IStudent
{
    string DisplayInformation();
}

public class Student : IStudent
{
    public string Name { get; set; }

    public string Grade { get; set; }

    public int Age { get; set; }

    public virtual string DisplayInformation()
    {
        return $"{Name} - {Age} years old is in {Grade} grade";
    }
}

public class StudentDecorator : Student
{
    private Student _student;

    public StudentDecorator(Student student)
    {
        _student = student;
    }

    public override string DisplayInformation()
    {
        return _student.DisplayInformation();
    }
}

public class ScienceStudentDecorator : StudentDecorator
{
    public string Labs { get; set; }

    public ScienceStudentDecorator(Student student) : base(student)
    {
    }

    public override string DisplayInformation()
    {
        var info =  base.DisplayInformation();
        return $"{info}. Labse are {Labs}";
    }
}

我正在那样装饰学生:

        var student = new Student
        {
            Age = 15,
            Grade = "Fourth",
            Name = "John"
        };

        var scienceStudent = new ScienceStudentDecorator(student)
        {
            Labs = "Biology, History, Physics"
        };

        Console.WriteLine(scienceStudent.DisplayInformation());

        Console.Read();

让我想知道的是,如果我将ScienceStudentDecorator更改为继承并保持Student,它的工作方式完全相同。我还在装饰学生。我刚和学生装饰员一起跳过仪式。我的问题是我误解了这个概念吗?

更改版本:

public class ScienceStudentDecorator : Student
{
    private Student _student;

    public string Labs { get; set; }

    public ScienceStudentDecorator(Student student)
    {
        _student = student;
    }

    public override string DisplayInformation()
    {
        var info =  _student.DisplayInformation();
        return $"{info}. Labse are {Labs}";
    }
}

Student和ScienceDecorator的创建完全相同。

2 个答案:

答案 0 :(得分:2)

首先;你发现了替代方案,这让我说你理解了这个概念。

您缺少的部分是继承不良的部分。嗯,那就是;如果你想复制界面而不是行为。

  

装饰器模式的关键点在于它是一个alternative to inheritance,具有在运行时改变和扩展行为的能力,并且没有绑定到具有特定版本或其他依赖关系的某个基类。

这就是为什么,您应该仅基于ScienceStudentDecorator界面制作IStudent并使用IStudent代替Student进行装饰(尽管.net的{{1}类往往会破坏这个规则。[我也倾向于创建一个Stream只是为了让装饰变得简单])

我想指出的另一件事是,abstract NullStudent对象下面没有必要。以下代码也足够了,请注意;非行为继承:

decorator

<强>更新 为了更清楚,让我们检查以下案例:

想象一下,你有一个public interface IStudent //this would rather be called an IInformationDisplayer { string DisplayInformation(); } public class Student : IStudent { public string Name, Grade, Age, etc... { get; set; } private IStudent _student = null; public Student() { } public Student(IStudent student) { _student = student; } public string DisplayInformation() { return $"{_student?.DisplayInformation()}" + $"{Name} - {Age} years old is in {Grade} grade"; } } public class ScienceStudent : IStudent //it's still a decorator { public string Labs { get; set; } private IStudent _student; public ScienceStudentDecorator(IStudent student) { _student = student; } public string DisplayInformation() { var info = _student?.DisplayInformation(); return $"{info}. Labse are {Labs}"; } } 类型:

IDrawable

接下来我们有一个我们想要绘制的矩形(请注意,这也可能是一个房子或墙,一个FileStream或一个MemoryStream,你认为它,你会命名它。)

但是,让我们保持一个矩形:

public interface IDrawable
{ 
    //maybe with some additional properties as dimensions and position
    void Draw();
} 

没什么特别的。但我们假设我们想在矩形周围画一个边框。

让我们创建一个可绘制的边框:

public class Rectangle : IDrawable
{
    private IDrawable _drawable;
    public class Rectangle(IDrawable drawable)
    {
      _drawable = drawable; //just to make it uniform
    }

    private InernalDraw() { ... }

    public void Draw()
    {
        //do the drawing magic
        InernalDraw(); //some drawing code
        //and do something with the decorated item
        _drawable?.Draw();
    }
}

现在,让我们考虑以下代码:

public class Border : IDrawable
{
    private IDrawable _drawable;
    public class Border(IDrawable drawable)
    {
      _drawable = drawable;
    }

    private InternalDrawWithSomeSpecialLogicAndStuff() { ... }

    public void Draw()
    {
        //draw the decorated item:
        _drawable?.Draw();

        //and work out some magic to draw a border around it,
        //note that properties as dimensions would be helpful.
        InternalDrawWithSomeSpecialLogicAndStuff();
    }
}

答案 1 :(得分:2)

装饰器模式的概念是从继承和松散耦合中获得替代。 你有装饰的基本概念。我的建议是为基础装饰器提供一个级别的抽象,它作为一个基础给我们的位置,它将默认接口所需的任何装饰器行为,而具体的装饰器实现将只关注装饰。

public interface IStudent
{
    string Name {get;}

    string DisplayInformation();
}

public class Student : IStudent
{
    public string Name { get; set; }

    public string DisplayInformation()
    {
        return $"{Name} - {Age} years old is in {Grade} grade";
    }
}



/// Base for decorators which stores our base in constructor
/// Gives default behaviour to all props and methods required by Interface
public abstract class StudentDecorator : IStudent
{
    protected IStudent BaseStudent {get;}

    protected StudentDecorator(IStudent student)
    {
        BaseStudent = student;
    }

    public virtual string Name { get { return BaseStudent.Name;} }

    public virtual string DisplayInformation()
    {
        return BaseStudent.DisplayInformation();
    }

/// Concrete decorator, we don't need to override Name property
public class ScienceStudentDecorator : StudentDecorator
{
    public string Labs { get; set; }

    public ScienceStudentDecorator(IStudent student) : base (student)
    {
        ///Behaviour here done by abstract constructor
    }

    public override string DisplayInformation()
    {
        var info =  BaseStudent?.DisplayInformation();
        return $"{info}. Labse are {Labs}";
    }
}