Phương thức ảo C#

Chào mn, mình có 1 hình vuông là lớp kế thừa của lớp hình chữ nhật. Mình có 2 phương thức override như này có giống nhau không ạ, cả 2 đều ra kq giống nhau. Mọi người cho ý kiến về về 2 cách này ạ. Cảm ơn mn giúp đỡ.
Cách 1:

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

namespace KeThua
{
    class HinhVuong:HinhChuNhat
    {
        public HinhVuong(int c):base(c,c)
        {

        }
        public HinhVuong():base()
        { }
        
        override public int Dai
        {
            get { return m_dai; }
            set { m_dai = value;
                m_rong = m_dai; }
        }
        override public int Rong
        {
            get { return m_rong; }
            set { m_rong = value;
                m_dai = m_dai; }
        }
    }
    
}

Cách 2:

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

namespace KeThua
{
    class HinhVuong:HinhChuNhat
    {
        public HinhVuong(int c):base(c,c)
        {

        }
        public HinhVuong():base()
        { }
        public override int Dai
        {
            get
            {
                return base.Dai;
            }
            set
            {
                base.Dai = value;
                base.Rong = base.Dai;
            }
        }
        public override int Rong
        {
            get
            {
                return base.Rong;
            }
            set
            {
                base.Rong = value;
                base.Dai = base.Rong;
            }
        }
       
    }
    
}

Ca này kinh điển luôn rồi :smiley: theo nguyên lí thay thế Liskov (L trong SOLID) thì không bao h chấp nhận được.

1 Like

nói rõ hơn được không ạ, tại kiến thức mình hơi hẹp, hjhj

HinhVuong không thể kế thừa HinhChuNhatHinhVuong không thể thay đổi độc lập chiều dài và chiều rộng.

thêm vấn đề nữa rồi, bài nay do ông Thầy mình dạy, cách 1 do Thầy làm, cách 2 do mình làm giờ bạn nói không thể kế thừa. Mình tin ai bây giờ.Nhưng theo mình hiểu là hình vuông là hình chữ nhật do 2 cạnh nó bằng nhau thôi á.

Kế thừa thì cũng được, nhưng mà nó không hợp lý về mặt lập trình. HCN thì có 2 thuộc tính cơ bản là width và height, còn hình vuông chỉ có edgeLength. Nếu làm như bạn, hình vuông override setter để khi set chiều dài chiều rộng thì nó set lẫn nhau cũng được, nhưng mà nó không hay. Một số phương thức của HCN khi sử dụng với hình vuông sẽ là thừa.

Nếu là mình thì mình làm một base interface cho HCN, cả HCN và hình vuông đều implement nó.

2 Likes

Hi rogp10.
Kế thừa cũng được vì hình vuông cũng là hình chữ nhật.

Khổ, cái bài này nó kinh điển rồi. Không phải cứ X là Y thì dùng thừa kế, đặc biệt là khi Y không trừu tượng.

Nguyên lí Liskov có thể hiểu là để khi duyệt qua một mớ đối tượng superclass, ta không bao h phải sử dụng đến typeof hay các lệnh có chức năng tương tự reinterpret_cast v.v. Phát biểu chuẩn hơn thì nó nghĩa là: subclass không được siết chặt pre-condition (đặt lên trên các phương thức của nó) hay mở rộng post-condition của superclass, và phải duy trì các bất biến của superclass.

VD: nếu tăng chiều dài lên gấp 3 lần thì diện tích phải tăng gấp 3 lần, nhưng với hình vuông thì sẽ không đúng vì chiều cao cũng phải tăng theo. Vậy là toạch vì vi phạm post-condition.

Thêm vào đó subclass không được văng exception trong một phương thức nếu superclass không văng exception trong đó, và subclass không được phá immutability (nghĩa là không phá const VÀ nếu superclass không cho set thì subclass cũng không được set).

4 Likes

Không phản đối gì, cơ mà “Readability counts”, thay vì hình vuông kế thừa hình chữ nhật thì có thể hình vuông và hình chữ nhật kế thừa hình tứ giác có phải đỡ hack não hơn không :))

Bạn biết lý do không? trả lời vậy thì ai mà biết cách xử lý ?

Ví dụ này phân tích kĩ hơn thì nó ntn:

  • Hình chữ nhật có thể co giãn (resizable)
    – Có chiều dài length và chiều rộng width { get; set; } và phải là số dương.
    – Ràng buộc: chỉ xét setLength() thì trước khi set chiều dài đưa vào phải là số dương, và sau đó chiều rộng không đổi.
  • Hình vuông có thể co giãn, thừa kế HCN
    – Thừa kế lại hai thuộc tính.
    – Bất biến: chiều dài == chiều rộng
    – Ràng buộc: tương tự nhưng chiều rộng phải đổi theo.

Vậy theo Liskov là không chấp nhận được.

1 Like

Xét trên các khái niệm trong OOP. Nếu có class “Đa giác lồi” ta không thể kế thừa nó mà không vi phạm tính kế thừa trong class “Hình chữ nhật” do các ràng buộc đặc trưng khiến ta buộc phải viết lại hoàn toàn thay vì mở rộng một số phương thức. Tương tự với class “Hình chữ nhật” và class “Hình vuông”.

Theo mình nghĩ, “là hình vuông” chỉ là một trong các tính chất có thể có của “Hình chữ nhật”. Class Rectangle chỉ cần công thức isSquare() là đủ. Cả class Rectangle và class Square đều implement interface IRectangle với các phương thức tính chu vi, diện tích, đường chéo, tìm trọng tâm…

83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?